-- SHA - Provide an idealized interface to the US Secure Hash Algorithm 1 and 2 family of functions. -- Copyright (C) 2020,2023 Prince Trippy . -- 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 . with Interfaces; -- These Interfaces types are invaluable when writing code which will interoperate. -- The SHA package originally would've held those four Bit, Octet, Bit_Array, and Octet_Array types. -- However, this grew to displease me, and so it only holds packages and never anything beyond such. package SHA is -- The SHA package is used to hold reusable generics subprograms in its private part. -- These SHA1, SHA256, SHA224, SHA384, and SHA512 children packages share an identical interface. -- Therefore, comments are omitted in all but this SHA1 package, as anything else is superfluous. -- I originally wanted to have a generic package, but it needed showing details I'll keep hidden. -- I considered implementing String subprograms as well, but alignment requirements prevented me. -- Each of these packages equally supports three different units: bits, octets, and lastly words. -- That bit type is that most inherent and pure, allowing for any possible invocation to be made. -- That octet type is a compromise with reality, and exists because octets are popular, nowadays. -- The word type exists, for the algorithms are defined in terms thereof; they're most efficient. package SHA1 is -- The Word types for SHA-256 and SHA-512 are incompatible, but can share the same name still. -- This is a more elegant solution than another name for an Interfaces.Unsigned_64 array type. type Bit is mod 2; for Bit'Size use 1; subtype Octet is Interfaces.Unsigned_8; subtype Word is Interfaces.Unsigned_32; -- Unfortunately, the Bit_Array type can't be used between packages sans Unchecked_Conversion. -- The Octet_Array type is trivial to use between these packages, as conversion is sufficient. -- The Word_Array type is usable between packages only in the cases where it would make sense. -- Without an Interfaces subtype, the Bit_Array type is the least useful of the three, anyway. type Bit_Array is array (Positive range <>) of Bit; type Octet_Array is array (Positive range <>) of Octet; type Word_Array is array (Positive range <>) of Word; -- All of these arrays will be compatible, and must have the most extreme alignment presented. -- I believe it should be unnecessary to specify a Component_Size attribute, for any of these. pragma Pack ( Bit_Array); for Bit_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack (Octet_Array); for Octet_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack ( Word_Array); for Word_Array'Alignment use Interfaces.Unsigned_64'Alignment; -- I find these named ranges to be distasteful; however, they're useful for other subprograms. subtype Bit_Block_Range is Positive range 1 .. 512; subtype Octet_Block_Range is Positive range 1 .. 64; subtype Word_Block_Range is Positive range 1 .. 16; subtype Bit_Block is Bit_Array ( Bit_Block_Range); subtype Octet_Block is Octet_Array (Octet_Block_Range); subtype Word_Block is Word_Array ( Word_Block_Range); -- My design foresaw these types to be required since some digests require further processing. -- Internally these types are exactly alike; the latter merely exists to force a stop to work. type Status is private; type Digest is private; -- Unfortunately, Ada 1995 seems to be unable to give such variables default values, for ease. Initial_Status : constant Status; -- These are the simplest of my given interfaces, and rightfully so; these permit no mistakes. -- Always use these functions, if data fits in memory, and there be no special considerations. -- The length of a message will always be a multiple of the chosen unit, the 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 parts that need not even exist all at once. -- These functions exist to allow the first hash to be done 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 one invocation may be used with seperately-initialized variables. -- The procedure is rather naturally more likely to be a tad 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); -- These functions exist only to serve an optimized implementation of HMAC and similar things. -- This interface allows for overriding all important characteristics sans a reimplementation. -- Furthermore, this interface can efficiently implement those functions that return a Digest. -- The alternation from this is reimplementation of the prime SHA loop or array concatenation. function Hash (State : in Status; Data : in Bit_Array; Bit_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Octet_Array; Octet_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Word_Array; Word_Length : in Natural) return Digest; -- The SHA-1 and SHA-2 family padding function spits one, filling zeroes, then message length. -- My design requires another, reserved block for overflow, which is wasteful, but easier use. -- That Primary block will always need to be hashed, and Auxiliary if Overflow be set to True. -- I found it to be easy to provide three Pad varieties with Ada generics, with a restriction. -- Each of these Pad procedures will pad only to a size which is a multiple of the block unit. -- I noticed this seemingly obvious restriction from how easily I could make it a generic Pad. -- The body stays the same, and merely marks a constant for the delimiting bit of the padding. -- The alternation from this design is a lone Pad procedure which only accepts a size in bits. -- The prime downside is that a block must be translated to that appropriate unit granularity. -- In practice this isn't an issue in any way, as the preferred unit will already be 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); -- There's need for neither To_Status, nor a way to generate a Status, so this isn't provided. -- However, the ability to craft a Status value is required to handle some variant algorithms. -- In particular, this package doesn't support the SHA-512/t variant family of the algorithms. -- I may easily add this, but felt like not thinking of names for that Status word array type. -- These functions only exist for extracting and actually using those resulting Digest values. -- For efficiency purposes I may later decide to introduce subtypes for such function results. -- Now or after such, such subtypes shouldn't be used directly, but to initialize indefinites. function To_Digest (State : in Status) return Digest; -- This is useful, to prevent tampering. function To_String (Datum : in Digest) return String; -- This is straightforward, from octets. function To_Bits (Datum : in Digest) return Bit_Array; -- Surely, this could have utility. function To_Octets (Datum : in Digest) return Octet_Array; -- This greatly helps in To_String. function To_Words (Datum : in Digest) return Word_Array; -- This is direct and least useful. private type Cycle is new Integer range 0 .. 79; type Status is array (Integer range 0 .. 4) of Word; type Digest is new Status; Initial_Status : constant Status := (16#6745_2301#, 16#EFCD_AB89#, 16#98BA_DCFE#, 16#1032_5476#, 16#C3D2_E1F0#); end SHA1; package SHA256 is type Bit is mod 2; for Bit'Size use 1; subtype Octet is Interfaces.Unsigned_8; subtype Word is Interfaces.Unsigned_32; type Bit_Array is array (Positive range <>) of Bit; type Octet_Array is array (Positive range <>) of Octet; type Word_Array is array (Positive range <>) of Word; pragma Pack ( Bit_Array); for Bit_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack (Octet_Array); for Octet_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack ( Word_Array); for Word_Array'Alignment use Interfaces.Unsigned_64'Alignment; subtype Bit_Block_Range is Positive range 1 .. 512; subtype Octet_Block_Range is Positive range 1 .. 64; subtype Word_Block_Range is Positive range 1 .. 16; subtype Bit_Block is Bit_Array ( Bit_Block_Range); subtype Octet_Block is Octet_Array (Octet_Block_Range); subtype Word_Block is Word_Array ( Word_Block_Range); type Status is private; type Digest is private; Initial_Status : constant Status; function Hash (Data : in Bit_Array) return Digest; function Hash (Data : in Octet_Array) return Digest; function Hash (Data : in Word_Array) return Digest; 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; 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); function Hash (State : in Status; Data : in Bit_Array; Bit_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Octet_Array; Octet_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Word_Array; Word_Length : in Natural) return Digest; 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); function To_Digest (State : in Status) return Digest; function To_String (Datum : in Digest) return String; function To_Bits (Datum : in Digest) return Bit_Array; function To_Octets (Datum : in Digest) return Octet_Array; function To_Words (Datum : in Digest) return Word_Array; private subtype Cycle is Integer range 0 .. 63; -- It's pleasant to be able to reuse both KK, and KKK. subtype Status_Index is Integer range 0 .. 7; -- This is necessary for generic instantiations. type Status is array (Status_Index) of Word; type Digest is new Status; 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#); end SHA256; package SHA224 is type Bit is mod 2; for Bit'Size use 1; subtype Octet is Interfaces.Unsigned_8; subtype Word is Interfaces.Unsigned_32; type Bit_Array is array (Positive range <>) of Bit; type Octet_Array is array (Positive range <>) of Octet; type Word_Array is array (Positive range <>) of Word; pragma Pack ( Bit_Array); for Bit_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack (Octet_Array); for Octet_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack ( Word_Array); for Word_Array'Alignment use Interfaces.Unsigned_64'Alignment; subtype Bit_Block_Range is Positive range 1 .. 512; subtype Octet_Block_Range is Positive range 1 .. 64; subtype Word_Block_Range is Positive range 1 .. 16; subtype Bit_Block is Bit_Array ( Bit_Block_Range); subtype Octet_Block is Octet_Array (Octet_Block_Range); subtype Word_Block is Word_Array ( Word_Block_Range); type Status is private; type Digest is private; Initial_Status : constant Status; function Hash (Data : in Bit_Array) return Digest; function Hash (Data : in Octet_Array) return Digest; function Hash (Data : in Word_Array) return Digest; 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; 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); function Hash (State : in Status; Data : in Bit_Array; Bit_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Octet_Array; Octet_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Word_Array; Word_Length : in Natural) return Digest; 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); function To_Digest (State : in Status) return Digest; function To_String (Datum : in Digest) return String; function To_Bits (Datum : in Digest) return Bit_Array; function To_Octets (Datum : in Digest) return Octet_Array; function To_Words (Datum : in Digest) return Word_Array; private subtype Cycle is Integer range 0 .. 63; subtype Status_Index is Integer range 0 .. 7; type Status is array (Status_Index) of Word; type Digest is array (Integer range 0 .. 6) of Word; Initial_Status : constant Status := (16#C105_9ED8#, 16#367C_D507#, 16#3070_DD17#, 16#F70E_5939#, 16#FFC0_0B31#, 16#6858_1511#, 16#64F9_8FA7#, 16#BEFA_4FA4#); end SHA224; package SHA512 is type Bit is mod 2; for Bit'Size use 1; subtype Octet is Interfaces.Unsigned_8; subtype Word is Interfaces.Unsigned_64; type Bit_Array is array (Positive range <>) of Bit; type Octet_Array is array (Positive range <>) of Octet; type Word_Array is array (Positive range <>) of Word; pragma Pack ( Bit_Array); for Bit_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack (Octet_Array); for Octet_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack ( Word_Array); subtype Bit_Block_Range is Positive range 1 .. 1024; subtype Octet_Block_Range is Positive range 1 .. 128; subtype Word_Block_Range is Positive range 1 .. 16; subtype Bit_Block is Bit_Array ( Bit_Block_Range); subtype Octet_Block is Octet_Array (Octet_Block_Range); subtype Word_Block is Word_Array ( Word_Block_Range); type Status is private; type Digest is private; Initial_Status : constant Status; function Hash (Data : in Bit_Array) return Digest; function Hash (Data : in Octet_Array) return Digest; function Hash (Data : in Word_Array) return Digest; 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; 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); function Hash (State : in Status; Data : in Bit_Array; Bit_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Octet_Array; Octet_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Word_Array; Word_Length : in Natural) return Digest; 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); function To_Digest (State : in Status) return Digest; function To_String (Datum : in Digest) return String; function To_Bits (Datum : in Digest) return Bit_Array; function To_Octets (Datum : in Digest) return Octet_Array; function To_Words (Datum : in Digest) return Word_Array; private subtype Cycle is Integer range 0 .. 79; subtype Status_Index is Integer range 0 .. 7; type Status is array (Status_Index) of Word; type Digest is new Status; Initial_Status : constant Status := (16#6A09_E667_F3BC_C908#, 16#BB67_AE85_84CA_A73B#, 16#3C6E_F372_FE94_F82B#, 16#A54F_F53A_5F1D_36F1#, 16#510E_527F_ADE6_82D1#, 16#9B05_688C_2B3E_6C1F#, 16#1F83_D9AB_FB41_BD6B#, 16#5BE0_CD19_137E_2179#); end SHA512; package SHA384 is type Bit is mod 2; for Bit'Size use 1; subtype Octet is Interfaces.Unsigned_8; subtype Word is Interfaces.Unsigned_64; type Bit_Array is array (Positive range <>) of Bit; type Octet_Array is array (Positive range <>) of Octet; type Word_Array is array (Positive range <>) of Word; pragma Pack ( Bit_Array); for Bit_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack (Octet_Array); for Octet_Array'Alignment use Interfaces.Unsigned_64'Alignment; pragma Pack ( Word_Array); subtype Bit_Block_Range is Positive range 1 .. 1024; subtype Octet_Block_Range is Positive range 1 .. 128; subtype Word_Block_Range is Positive range 1 .. 16; subtype Bit_Block is Bit_Array ( Bit_Block_Range); subtype Octet_Block is Octet_Array (Octet_Block_Range); subtype Word_Block is Word_Array ( Word_Block_Range); type Status is private; type Digest is private; Initial_Status : constant Status; function Hash (Data : in Bit_Array) return Digest; function Hash (Data : in Octet_Array) return Digest; function Hash (Data : in Word_Array) return Digest; 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; 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); function Hash (State : in Status; Data : in Bit_Array; Bit_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Octet_Array; Octet_Length : in Natural) return Digest; function Hash (State : in Status; Data : in Word_Array; Word_Length : in Natural) return Digest; 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); function To_Digest (State : in Status) return Digest; function To_String (Datum : in Digest) return String; function To_Bits (Datum : in Digest) return Bit_Array; function To_Octets (Datum : in Digest) return Octet_Array; function To_Words (Datum : in Digest) return Word_Array; private subtype Cycle is Integer range 0 .. 79; subtype Status_Index is Integer range 0 .. 7; type Status is array (Status_Index) of Word; type Digest is array (Integer range 0 .. 5) of Word; Initial_Status : constant Status := (16#CBBB_9D5D_C105_9ED8#, 16#629A_292A_367C_D507#, 16#9159_015A_3070_DD17#, 16#152F_ECD8_F70E_5939#, 16#6733_2667_FFC0_0B31#, 16#8EB4_4A87_6858_1511#, 16#DB0C_2E0D_64F9_8FA7#, 16#47B5_481D_BEFA_4FA4#); end SHA384; private subtype Lesser_Cycle is Integer range 0 .. 63; subtype Larger_Cycle is Integer range 0 .. 79; type Lesser_Array is array (Lesser_Cycle) of Interfaces.Unsigned_32; type Larger_Array is array (Larger_Cycle) of Interfaces.Unsigned_64; KK : constant Lesser_Array := (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#); KKK : constant Larger_Array := (16#428A_2F98_D728_AE22#, 16#7137_4491_23EF_65CD#, 16#B5C0_FBCF_EC4D_3B2F#, 16#E9B5_DBA5_8189_DBBC#, 16#3956_C25B_F348_B538#, 16#59F1_11F1_B605_D019#, 16#923F_82A4_AF19_4F9B#, 16#AB1C_5ED5_DA6D_8118#, 16#D807_AA98_A303_0242#, 16#1283_5B01_4570_6FBE#, 16#2431_85BE_4EE4_B28C#, 16#550C_7DC3_D5FF_B4E2#, 16#72BE_5D74_F27B_896F#, 16#80DE_B1FE_3B16_96B1#, 16#9BDC_06A7_25C7_1235#, 16#C19B_F174_CF69_2694#, 16#E49B_69C1_9EF1_4AD2#, 16#EFBE_4786_384F_25E3#, 16#0FC1_9DC6_8B8C_D5B5#, 16#240C_A1CC_77AC_9C65#, 16#2DE9_2C6F_592B_0275#, 16#4A74_84AA_6EA6_E483#, 16#5CB0_A9DC_BD41_FBD4#, 16#76F9_88DA_8311_53B5#, 16#983E_5152_EE66_DFAB#, 16#A831_C66D_2DB4_3210#, 16#B003_27C8_98FB_213F#, 16#BF59_7FC7_BEEF_0EE4#, 16#C6E0_0BF3_3DA8_8FC2#, 16#D5A7_9147_930A_A725#, 16#06CA_6351_E003_826F#, 16#1429_2967_0A0E_6E70#, 16#27B7_0A85_46D2_2FFC#, 16#2E1B_2138_5C26_C926#, 16#4D2C_6DFC_5AC4_2AED#, 16#5338_0D13_9D95_B3DF#, 16#650A_7354_8BAF_63DE#, 16#766A_0ABB_3C77_B2A8#, 16#81C2_C92E_47ED_AEE6#, 16#9272_2C85_1482_353B#, 16#A2BF_E8A1_4CF1_0364#, 16#A81A_664B_BC42_3001#, 16#C24B_8B70_D0F8_9791#, 16#C76C_51A3_0654_BE30#, 16#D192_E819_D6EF_5218#, 16#D699_0624_5565_A910#, 16#F40E_3585_5771_202A#, 16#106A_A070_32BB_D1B8#, 16#19A4_C116_B8D2_D0C8#, 16#1E37_6C08_5141_AB53#, 16#2748_774C_DF8E_EB99#, 16#34B0_BCB5_E19B_48A8#, 16#391C_0CB3_C5C9_5A63#, 16#4ED8_AA4A_E341_8ACB#, 16#5B9C_CA4F_7763_E373#, 16#682E_6FF3_D6B2_B8A3#, 16#748F_82EE_5DEF_B2FC#, 16#78A5_636F_4317_2F60#, 16#84C8_7814_A1F0_AB72#, 16#8CC7_0208_1A64_39EC#, 16#90BE_FFFA_2363_1E28#, 16#A450_6CEB_DE82_BDE9#, 16#BEF9_A3F7_B2C6_7915#, 16#C671_78F2_E372_532B#, 16#CA27_3ECE_EA26_619C#, 16#D186_B8C7_21C0_C207#, 16#EADA_7DD6_CDE0_EB1E#, 16#F57D_4F7F_EE6E_D178#, 16#06F0_67AA_7217_6FBA#, 16#0A63_7DC5_A2C8_98A6#, 16#113F_9804_BEF9_0DAE#, 16#1B71_0B35_131C_471B#, 16#28DB_77F5_2304_7D84#, 16#32CA_AB7B_40C7_2493#, 16#3C9E_BE0A_15C9_BEBC#, 16#431D_67C4_9C10_0D4C#, 16#4CC5_D4BE_CB3E_42B6#, 16#597F_299C_FC65_7E2A#, 16#5FCB_6FAB_3AD6_FAEC#, 16#6C44_198C_4A47_5817#); end SHA; .