-- SHA256 - Provide an idealized interface to the US Secure Hash Algorithm 256 function. -- Copyright (C) 2020 Prince Trippy programmer@verisimilitudes.net. -- This program is free software: you can redistribute it and/or modify it under the terms of the -- GNU Affero General Public License version 3 as published by the Free Software Foundation -- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without -- even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU Affero General Public License for more details. -- You should have received a copy of the GNU Affero General Public License along with this program. -- If not, see . package SHA256 is -- Know I'll likely be copying these comments, across the packages, as applicable. -- These types may become a renaming from the SHA1 package once that's ready, perhaps compatible. -- It would be particularly inconvenient for an unnecessary package to be necessary for the Word. -- I may decide that SHA-1 will have its own Word and Word_Array, only sharing this with SHA-224. -- The following Bit, Octet, Bit_Array, and Octet_Array and comments derive from the SHA package. -- This overarching package merely contains the types every SHA function should and will support. -- While SHA-3 is defined in terms of bits, it's reasonable to support octets due to commonality. -- The Word types for SHA-256 and SHA-512 are incompatible, but can share names, so each has one. -- This is a much more elegant solution than having those types named Duotriget and Tetrasexaget. type Bit is mod 2; type Octet is mod 2**8; -- Similarly, a Word_Array type will be defined in those respective SHA-256 and SHA-512 packages. -- Nested packages are the single reason this SHA library will need Ada 1995 instead of Ada 1983. type Bit_Array is array (Positive range <>) of Bit; pragma Pack ( Bit_Array); type Octet_Array is array (Positive range <>) of Octet; pragma Pack (Octet_Array); type Word is mod 2**32; type Word_Array is array (Positive range <>) of Word; pragma Pack (Word_Array); -- Since these subtypes will necessarily be compatible, I may simply copy them for every package. subtype Bit_Block is Bit_Array (1 .. 512); subtype Octet_Block is Octet_Array (1 .. 64); subtype Word_Block is Word_Array (1 .. 16); -- With my design foresight these types are required, as some digests require further processing. -- Internally these types are exactly alike and the latter merely exists to force a stop to work. type Status is private; type Digest is private; -- Unfortunately, it seems Ada 1995 lacks the ability to give variables default values, for ease. Initial_Status : constant Status; -- These are the simplest of my provided interfaces, and rightfully so; these permit no mistakes. -- Always use these functions if data can fit in memory, and there are no special considerations. -- The length of the message will always be a multiple of the chosen unit, that prime difference. function Hash (Data : in Bit_Array) return Digest; function Hash (Data : in Octet_Array) return Digest; function Hash (Data : in Word_Array) return Digest; -- The block interfaces permit hashing the data in pieces, which need not even exist all at once. -- These functions exist to allow the first hash to be treated differently, using Initial_Status. function Hash (State : in Status; Data : in Bit_Block) return Status; function Hash (State : in Status; Data : in Octet_Block) return Status; function Hash (State : in Status; Data : in Word_Block) return Status; -- These procedures exist so a lone invocation may be used with seperately initialized variables. -- The procedure is rather naturally more likely to be slightly more efficient than the function. procedure Hash (State : in out Status; Data : in Bit_Block); procedure Hash (State : in out Status; Data : in Octet_Block); procedure Hash (State : in out Status; Data : in Word_Block); -- Unlike that SHA1, there are three Pad varieties, with only that for Bit enabling a bit-length. -- The SHA-1 and SHA-2 family padding function spits a one, filling zeroes, and a message length. -- My design requires a second block be reserved for overflow, which is wasteful, but easier use. -- The Primary block will always need to be hashed, and the Auxiliary if Overflow is set to true. -- For each, the length is in terms of the block unit, which makes it easier use without mistake. -- The prime downside is that a block must be translated to the appropriate unit granularity now. -- In practice, this isn't an issue in any way, as the preferred unit is likely already selected. procedure Pad (Primary : in out Bit_Block; Auxiliary : out Bit_Block; Bit_Length : in Natural; Overflow : out Boolean); procedure Pad (Primary : in out Octet_Block; Auxiliary : out Octet_Block; Octet_Length : in Natural; Overflow : out Boolean); procedure Pad (Primary : in out Word_Block; Auxiliary : out Word_Block; Word_Length : in Natural; Overflow : out Boolean); -- These functions clearly exist for extracting and actually using those resulting Digest values. -- There's no need for a To_Status nor a way to generate those otherwise, so this isn't provided. -- For efficiency purposes, I may decide later to introduce subtypes, for these function results. -- Now or after such, the subtypes shouldn't be used directly, but to initialize the indefinites. function To_Digest (State : in Status) return Digest; -- This is useful for preventing tampering. function To_String (Datum : in Digest) return String; -- This function internally uses To_Octets. function To_Bits (Datum : in Digest) return Bit_Array; -- Surely this is useful in some ways. function To_Octets (Datum : in Digest) return Octet_Array; -- This is mostly useful in To_String. function To_Words (Datum : in Digest) return Word_Array; -- It's the fastest, and least useful. private type Cycle is new Integer range 0 .. 63; type Status is array (Integer range 0 .. 7) of Word; -- It doesn't much matter if this is Packed. type Digest is new Status; -- Perhaps it's disappointing this is the simplest means for doing so. -- The following two procedures exist only to simplify definition for two of the Hash procedures. procedure Bits_To_Words (From : in Bit_Block; To : out Word_Block); procedure Octets_To_Words (From : in Octet_Block; To : out Word_Block); -- Unlike the SHA1, the Status is an array type, instead of a record, and my reasoning is simple. -- There's no particular difference with access, but I noticed an array would eliminate mistakes. -- It was simple enough to manage five Words, but the chance for mistakes only increases by size. Initial_Status : constant Status := (16#6A09_E667#, 16#BB67_AE85#, 16#3C6E_F372#, 16#A54F_F53A#, 16#510E_527F#, 16#9B05_688C#, 16#1F83_D9AB#, 16#5BE0_CD19#); -- I may as well place this here; I don't recall if I can use an incomplete constant here anyway. -- The SHA-256 and SHA-512 use what can be a lone K, but are separated for segmentation purposes. K : constant array (Cycle) of Word -- This is a basic source of pseudo-entropy derived by primes. := (16#428A_2F98#, 16#7137_4491#, 16#B5C0_FBCF#, 16#E9B5_DBA5#, 16#3956_C25B#, 16#59F1_11F1#, 16#923F_82A4#, 16#AB1C_5ED5#, 16#D807_AA98#, 16#1283_5B01#, 16#2431_85BE#, 16#550C_7DC3#, 16#72BE_5D74#, 16#80DE_B1FE#, 16#9BDC_06A7#, 16#C19B_F174#, 16#E49B_69C1#, 16#EFBE_4786#, 16#0FC1_9DC6#, 16#240C_A1CC#, 16#2DE9_2C6F#, 16#4A74_84AA#, 16#5CB0_A9DC#, 16#76F9_88DA#, 16#983E_5152#, 16#A831_C66D#, 16#B003_27C8#, 16#BF59_7FC7#, 16#C6E0_0BF3#, 16#D5A7_9147#, 16#06CA_6351#, 16#1429_2967#, 16#27B7_0A85#, 16#2E1B_2138#, 16#4D2C_6DFC#, 16#5338_0D13#, 16#650A_7354#, 16#766A_0ABB#, 16#81C2_C92E#, 16#9272_2C85#, 16#A2BF_E8A1#, 16#A81A_664B#, 16#C24B_8B70#, 16#C76C_51A3#, 16#D192_E819#, 16#D699_0624#, 16#F40E_3585#, 16#106A_A070#, 16#19A4_C116#, 16#1E37_6C08#, 16#2748_774C#, 16#34B0_BCB5#, 16#391C_0CB3#, 16#4ED8_AA4A#, 16#5B9C_CA4F#, 16#682E_6FF3#, 16#748F_82EE#, 16#78A5_636F#, 16#84C8_7814#, 16#8CC7_0208#, 16#90BE_FFFA#, 16#A450_6CEB#, 16#BEF9_A3F7#, 16#C671_78F2#); end SHA256; .