-- SHA1 - Provide an idealized interface to the US Secure Hash Algorithm 1 function. -- Copyright (C) 2019 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 SHA1 is -- I've decided to only support the thirty-two bit word as the basic unit here over those others. -- The units disadvantaged by this choice are all others and I figure bit and octet particularly. -- I made this decision, as I was realizing repetitive code, and didn't want to involve generics. -- I could avoid generics by writing word conversion functionality but didn't feel the want here. -- Perhaps I'll see every single one of my implementations of SHA1 making such a design decision. -- The word is chosen as the base unit as it is the base unit of that SHA1 algorithm description. -- I intend to, perhaps, coalesce my various SHA implementations into a single package, sometime. -- Perhaps I'll add more choices and make the various interfaces as orthogonal as can be in that. -- I may switch these out for the Interfaces.Unsigned_n types at a later time. type Bit is mod 2; type Octet is mod 2**8; type Word is mod 2**32; -- There's little good reason or point in trying to enforce the 2**64 message size limit of SHA1. -- I'm considering defining a Bit_Length type to make it harder to use an incorrect size in this. -- This type is intended solely for the Hashing variety which has all data to hash in the memory. type Bit_Array is array (Positive range <>) of Bit with pack; -- Do I need to pack with this? type Octet_Array is array (Positive range <>) of Octet with pack; type Word_Array is array (Positive range <>) of Word with pack; -- The subtype corresponds to the half-kibibyte block from the description of the SHA1 algorithm. subtype Word_Block is Word_Array (1 .. 16); -- These are actually the same type, yet I grew fond of this idea of transforming internal state. -- I'd figure this also reduces errors; so you use Status, until you're finished, and convert it. -- Perhaps I should make the default value of Status variables be Initial_Status. type Status is private; type Digest is private; Initial_Status : constant Status; -- This is that in-memory version of this interface, which is also rightfully that simplest here. -- The only downside to note is the SHA1 message length will be a multiple of thirty-two in this. -- This should always be used if the data to hash is already in memory. function Hash (Data : Word_Array) return Digest; -- This is that block interface which permits loading that data to hash in situ, not all at once. -- There is a function and a procedure variety for that case of how my Initial_Status is treated. -- It may be more convenient to treat the first Hashing differently and so use the function here. -- Alternatively, simply initialize a Status variable, manually, and then you use this procedure. -- I dislike explicit initialization functions, and so find this a much nicer interface for such. function Hash (State : Status; Data : Word_Block) return Status; procedure Hash (State : in out Status; Data : in Word_Block); -- This exists to pad the final block of data; Bit_Length determines where the padding is placed. -- A one will be placed at the end of the message, the remainder filled with zeroes and a length. -- In the case of Primary being insufficiently free, Overflow is true and Auxiliary is then used. -- Thus Overflow signals Auxiliary must also be used to obtain that correct SHA1 checksum digest. -- It's unfortunate that an otherwise unnecessary block is required, but this is rather easy use. -- As I no longer have varying units, this is a general interface which allows a bit granularity. procedure Pad (Primary : in out Word_Block; -- I may as well use new lines each item for this. Auxiliary : out Word_Block; Bit_Length : in Natural; Overflow : out Boolean); -- I've considered defining subtypes, so that these return results will be definite, but haven't. -- For the case where the utmost efficiency is required, I figure you set the bounds at the call. -- The String is 1 .. 40, the Bits 1 .. 160, the Octets 1 .. 20, and the Words are bounds 1 .. 5. -- I see no particular need for reverse conversion functions here. function To_Digest (State : Status) return Digest; function To_String (Datum : Digest) return String; function To_Bits (Datum : Digest) return Bit_Array; -- Bit(_Array) exist to be used for this. function To_Octets (Datum : Digest) return Octet_Array; -- Octet(_Array) are similarly used here. function To_Words (Datum : Digest) return Word_Array; private -- I need not care about the organization of any of this considering it may change at my leisure. type Status is record H0, H1, H2, H3, H4 : Word; end record; type Digest is new Status; -- I suppose this is that best way, to create an incompatible copycat. Initial_Status : constant Status := (H0 => 16#67452301#, H1 => 16#EFCDAB89#, H2 => 16#98BADCFE#, H3 => 16#10325476#, H4 => 16#C3D2E1F0#); type Cycle is new Integer range 0 .. 79; function K (T : Cycle) return Word; function F (T : Cycle; B, C, D : Word) return Word; end SHA1; .