1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
|
-- (C) Copyright 1999 by John Halleck,All rights reserved.
-- Basic Transformation functions of NSA's Secure Hash Algorithm
-- This is part of a project at http://www.cc.utah.edu/~nahaj/
package body SHA.Process_Data is
Default_Context : Context; -- Standard context for people that don't need
-- -- to hash more than one stream at a time;
---------------------------------------------------------------------------
-- Totally local functions.
-- Raw transformation of the data.
procedure Transform (Given : in out Context);
-- This is the basic work horse of the standard. Everything else here
-- is just frame around this.
-- Align data and place in buffer. (Arbitrary chunks.)
procedure Graft_On (Given : in out Context;
Raw : Unsigned_32;
Size : Bit_Index;
Increment_Count : Boolean := True);
---------------------------------------------------------------------------
-- On with the show -----------------------------------------
-- Quick and easy routine for the most common simple case.
function Digest_A_String (Given : String)
return Digest is
Temp : Context; -- Let's make this totally independent of anything
-- -- else the user may be doing.
Result : Digest;
begin
Initialize (Temp);
for I in Given'First .. Given'Last loop
Add (Byte (Character'Pos (Given (I))), Temp);
end loop;
Finalize (Result, Temp);
return Result;
end Digest_A_String;
-- Start out the buffer with a good starting state.
-- Note that there are assumptions ALL over the code that the
-- buffer starts out with zeros.
procedure Initialize is
begin
if Default_Context.Initialized then
raise SHA_Second_Initialize;
end if;
Default_Context := Initial_Value;
Default_Context.Initialized := True;
end Initialize;
procedure Initialize (Given : in out Context) is
begin
if Given.Initialized then
raise SHA_Second_Initialize;
end if;
Given := Initial_Value;
Given.Initialized := True;
end Initialize;
-- Procedures to add to the data being hashed.
procedure Add (Data : Bit) is
begin
if not Default_Context.Initialized then
raise SHA_Not_Initialized;
end if;
Graft_On (Default_Context, Unsigned_32 (Data), 1);
end Add;
procedure Add (Data : Bit; Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
Graft_On (Given, Unsigned_32 (Data), 1);
end Add;
procedure Add (Data : Byte) is
begin
if not Default_Context.Initialized then
raise SHA_Not_Initialized;
end if;
Graft_On (Default_Context, Unsigned_32 (Data), 8);
end Add;
procedure Add (Data : Byte; Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
Graft_On (Given, Unsigned_32 (Data), 8);
end Add;
procedure Add (Data : Word) is
begin
if not Default_Context.Initialized then
raise SHA_Not_Initialized;
end if;
Graft_On (Default_Context, Unsigned_32 (Data), 16);
end Add;
procedure Add (Data : Word; Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
Graft_On (Given, Unsigned_32 (Data), 16);
end Add;
procedure Add (Data : Long) is
begin
if not Default_Context.Initialized then
raise SHA_Not_Initialized;
end if;
Graft_On (Default_Context, Unsigned_32 (Data), 32);
end Add;
procedure Add (Data : Long; Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
Graft_On (Given, Unsigned_32 (Data), 32);
end Add;
procedure Add (Data : Long; Size : Bit_Index) is
begin
if not Default_Context.Initialized then
raise SHA_Not_Initialized;
end if;
Graft_On (Default_Context, Unsigned_32 (Data), Size);
end Add;
procedure Add (Data : Long; Size : Bit_Index;
Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
Graft_On (Given, Unsigned_32 (Data), Size);
end Add;
-- Get the final digest.
function Finalize return Digest is
Result : Digest;
begin
Finalize (Result, Default_Context);
return Result;
end Finalize;
procedure Finalize (Result : out Digest) is
begin
Finalize (Result, Default_Context);
end Finalize;
procedure Finalize (Result : out Digest; Given : in out Context) is
begin
if not Given.Initialized then raise SHA_Not_Initialized; end if;
-- The standard requires the Data be padded with a single 1 bit.
Graft_On (Given, 1, 1, False);
-- We may have to make room for the count to be put on the last block.
if Given.Next_Word >= Given.Data'Last - 1 then -- Room for the count?
if not (Given.Next_Word = Given.Data'Last - 1
and Given.Remaining_Bits = 32) then
Transform (Given);
end if;
end if;
-- Ok, now we can just add the count on.
Given.Data (Given.Data'Last - 1) := Given.Count_High;
Given.Data (Given.Data'Last) := Given.Count_Low;
-- And now we just transform that.
Transform (Given);
-- Ok, we are done.
Given.Initialized := False; -- One aught not to reused this without
-- appropriate re-initialization.
Result := Given.Current;
end Finalize;
---------------------------------------------------------------------------
-- Actually put the bits we have into the buffer properly aligned.
procedure Graft_On (Given : in out Context;
Raw : Unsigned_32;
Size : Bit_Index;
Increment_Count : Boolean := True) is
Offset : Integer range -31 .. 32; -- How far to move to align this?
Overflow : Bit_Index := 0; -- How much is into the next word?
Remainder : Unsigned_32 := 0; -- What data has to be done in cleanup?
Value : Unsigned_32 := Raw; -- What value are we Really working with?
begin
pragma Inline (Graft_On);
-- Huh?
if Size = 0 then return; end if;
-- How do we have to align the data to fit?
Offset := Integer (Given.Remaining_Bits) -- Amount used
- Integer (Size); -- Minus amount we have.
if Offset > 0 then
Value := Shift_Left (Value, Offset);
elsif Offset < 0 then
Remainder := Shift_Left (Value, 32 + Offset);
-- -- Really "- -Offset"
Value := Shift_Right (Value, -Offset);
Overflow := Bit_Index (-Offset);
end if;
-- Insert the actual value into the table.
Given.Data (Given.Next_Word) := Given.Data (Given.Next_Word) or Value;
-- Update where we are in the table.
if Offset > 0 then -- Not on a word boundry
Given.Remaining_Bits := Given.Remaining_Bits - Size;
elsif Given.Next_Word < Data_Buffer'Last then
Given.Next_Word := Given.Next_Word + 1;
Given.Remaining_Bits := 32;
else
Transform (Given); -- Also clears everything out of the buffer.
end if;
-- Handle anything that overflows into the next word.
if Overflow /= 0 then
Given.Data (Given.Next_Word) := Given.Data (Given.Next_Word)
or Remainder;
Given.Remaining_Bits := 32 - Overflow;
end if;
if Increment_Count then
Given.Count_Low := Given.Count_Low + Unsigned_32 (Size);
if Given.Count_Low < Unsigned_32 (Size) then
Given.Count_High := Given.Count_High + 1;
if Given.Count_High = 0 then raise SHA_Overflow; end if;
-- The standard is only defined up to a total size of what
-- you are hashing of 2**64 bits.
end if;
end if;
end Graft_On;
---------------------------------------------------------------------------
-- The actual SHA transformation of a block of data.
-- Yes, it is cryptic... But it is a pretty much direct transliteration
-- of the standard, variable names and all.
procedure Transform (Given : in out Context) is
Temp : Unsigned_32;
-- Buffer to work in.
type Work_Buffer is array (0 .. 79) of Unsigned_32;
W : Work_Buffer;
-- How much is filled from the data, how much is filled by expansion.
Fill_Start : constant := Work_Buffer'First + Data_Buffer'Length;
Data_End : constant := Fill_Start - 1;
A : Unsigned_32 := Given.Current (0);
B : Unsigned_32 := Given.Current (1);
C : Unsigned_32 := Given.Current (2);
D : Unsigned_32 := Given.Current (3);
E : Unsigned_32 := Given.Current (4);
begin
for I in Work_Buffer'First .. Data_End loop
W (I) := Given.Data (Word_Range (I));
end loop;
for I in Fill_Start .. Work_Buffer'Last loop
W (I) := Rotate_Left (
W (I - 3) xor W (I - 8) xor W (I - 14) xor W (I - 16),
1
);
end loop;
for I in Work_Buffer'Range loop
Temp := W (I) + Rotate_Left (A, 5) + E;
case I is
when 0 .. 19 => Temp := Temp
+ 16#5A827999# + ((B and C) or ((not B) and D));
when 20 .. 39 => Temp := Temp
+ 16#6ED9EBA1# + (B xor C xor D);
when 40 .. 59 => Temp := Temp
+ 16#8F1BBCDC# + ((B and C) or (B and D) or (C and D));
when 60 .. 79 => Temp := Temp
+ 16#CA62C1D6# + (B xor C xor D);
end case;
E := D;
D := C;
C := Rotate_Right (B, 2); -- The standard really says rotate left 30.
B := A;
A := Temp;
end loop;
Given.Current := (Given.Current (0) + A,
Given.Current (1) + B,
Given.Current (2) + C,
Given.Current (3) + D,
Given.Current (4) + E
);
Given.Remaining_Bits := 32;
Given.Next_Word := 0;
Given.Data := (others => 0); -- *THIS MUST BE DONE*
end Transform;
end SHA.Process_Data;
|