File: sha-process_data.adb

package info (click to toggle)
libaws 2.2dfsg-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 7,624 kB
  • ctags: 1,173
  • sloc: ada: 61,829; ansic: 6,483; makefile: 1,282; xml: 196; sh: 119; java: 112; python: 66; sed: 40
file content (322 lines) | stat: -rw-r--r-- 10,869 bytes parent folder | download | duplicates (5)
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;