tree checksum vpatch file split hunks
all signers: diana_coman
antecedents: eucrypt_ch9_keccak_endianness
press order: 
| eucrypt_genesis | diana_coman | 
| eucrypt_ch6_keccak_permutations | diana_coman | 
| eucrypt_ch7_keccak_sponge | diana_coman | 
| eucrypt_ch9_keccak_endianness | diana_coman | 
| eucrypt_ch10_oaep_tmsr | diana_coman | 
patch: 
(5 . 8)(5 . 8)
  5 
  6 -- public function, sponge
  7   procedure Sponge( Input      : in Bitstream;
  8                     Block_Len  : in Keccak_Rate;
  9                     Output     : out Bitstream) is
 10                     Output     : out Bitstream;
 11                     Block_Len  : in Keccak_Rate := Default_Bitrate ) is
 12     Internal  : State := (others => (others => 0));
 13   begin
 14     --absorb input into sponge in a loop on available blocks, including padding
- 63A6A9F8168017265C7CCF9B3D7DFFD7C3CD21F529AE88993C3B05E0DCAFF9530C68B3420B58F643FF2425F575C66E9E0DF19ED25C8A38F56A0D1E713E27B15C(13 . 6)(13 . 9)-
19 --therefore keccak function 1600 with current
20 --constants (5*5*2^6)
21
22 Default_Bitrate: constant := 1344; --max bits the sponge can eat/spit without
23 --needing to scramble the state
24
25 --constants: dimensions of keccak state and number of rounds
26 XY_Length: constant := 5;
27 Z_Length: constant := 2**Keccak_L;
(49 . 12)(52 . 12)
29 -- public function, the sponge itself
30 -- Keccak sponge structure using Keccak_Function, Pad and a given bitrate;
31 -- Input - the stream of bits to hash (the message)
32 -- Output - a bitstream of desired size for holding output
33 -- Block_Len - the bitrate to use; this is effectively the block length
34 -- for splitting Input AND squeezing output between scrambles
35 -- Output - a bitstream of desired size for holding output
36 procedure Sponge(Input : in Bitstream;
37 Block_Len : in Keccak_Rate;
38 Output : out Bitstream);
39 Output : out Bitstream;
40 Block_Len : in Keccak_Rate := Default_Bitrate );
41
42 private
43 -- these are internals of the keccak implementation, not meant to be directly
(0 . 0)(1 . 202)
 48 -- S.MG, 2018
 49 
 50 package body SMG_OAEP is
 51 
 52   procedure HashKeccak( Input     : in String;
 53                         Output    : out String;
 54                         Block_Len : in Keccak_Rate := Default_Bitrate) is
 55     BIn  : Bitstream( 0 .. Input'Length * 8 - 1 );
 56     BOut : Bitstream( 0 .. Output'Length * 8 - 1 ); 
 57   begin
 58     ToBitstream( Input, BIn);
 59     Sponge( BIn, BOut, Block_Len);
 60     ToString( BOut, Output );
 61   end HashKeccak;
 62 
 63   function Hash( Input     : Interfaces.C.Char_Array;
 64                  LenIn     : Interfaces.C.size_t;
 65                  LenOut    : Interfaces.C.size_t;
 66                  Block_Len : Interfaces.C.int := Default_Bitrate)
 67                  return Interfaces.C.Char_Array is
 68     AdaLenIn  : Natural := Natural(LenIn);
 69     AdaLenOut : Natural := Natural(LenOut);
 70     InStr     : String( 0 .. AdaLenIn-1 )  := (others => '0'); 
 71     OutStr    : String( 0 .. AdaLenOut-1 ) := (others => '0');
 72     COut      : Interfaces.C.Char_Array( 0 .. LenOut-1 );
 73     Count     : Natural := AdaLenOut;
 74     CCount    : Interfaces.C.size_t := LenOut;
 75   begin
 76     Interfaces.C.To_Ada( Input, InStr, AdaLenIn );
 77     HashKeccak( InStr, OutStr, Keccak_Rate(Block_Len) );
 78     Interfaces.C.To_C( OutStr, COut, CCount );
 79     return COut;
 80   end Hash;
 81 
 82   -- conversion between types
 83   procedure ToString(B: in Bitstream; S: out String ) is
 84     N   : Natural;
 85     Pos : Natural;
 86   begin
 87     Pos := B'First;
 88     for I in S'Range loop
 89       N := Natural( B( Pos     ) ) +
 90            Natural( B( Pos + 1 ) ) * 2 +
 91            Natural( B( Pos + 2 ) ) * 4 +
 92            Natural( B( Pos + 3 ) ) * 8 +
 93            Natural( B( Pos + 4 ) ) * 16 +
 94            Natural( B( Pos + 5 ) ) * 32 +
 95            Natural( B( Pos + 6 ) ) * 64 +
 96            Natural( B( Pos + 7 ) ) * 128;
 97       Pos := Pos + 8;
 98       S( I ) := Character'Val( N );
 99     end loop;
100   end ToString;
101 
102   procedure ToBitstream(S: in String; B: out Bitstream ) is
103     V   : Unsigned_8;
104     Pos : Natural;
105   begin
106     Pos := B'First;
107     for C of S loop
108       V := Character'Pos( C );
109       B( Pos     ) := Bit( V and 1 );
110       B( Pos + 1 ) := Bit( Shift_Right( V, 1 ) and 1 );
111       B( Pos + 2 ) := Bit( Shift_Right( V, 2 ) and 1 );
112       B( Pos + 3 ) := Bit( Shift_Right( V, 3 ) and 1 );
113       B( Pos + 4 ) := Bit( Shift_Right( V, 4 ) and 1 );
114       B( Pos + 5 ) := Bit( Shift_Right( V, 5 ) and 1 );
115       B( Pos + 6 ) := Bit( Shift_Right( V, 6 ) and 1 );
116       B( Pos + 7 ) := Bit( Shift_Right( V, 7 ) and 1 );
117 
118       Pos := Pos + 8;
119     end loop;
120   end ToBitstream;
121 
122   -- padding & formatting of maximum 1960 bits of the given String 
123   -- uses TMSR's OAEP schema:
124   -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message
125   --    where sz1 and sz2 store the length of the message in bits
126   --    the random octets before message are padding to make OAEP_LENGTH_OCTETS
127   -- 2. R = OAEP_HALF_OCTETS random bits
128   -- 3. X = M00 xor hash(R)
129   -- 4. Y = R xor hash(X)
130   -- 5. Result is X || Y 
131   -- NB: the Entropy parameter should be random octets from which this method 
132   -- will use as many as required for the OAEP encryption of given Msg
133   -- NB: at MOST OAEP_LENGTH_OCTETS - 11 octets of Msg! (Msg at most 1960 bits)
134   procedure OAEP_Encrypt( Msg     : in String;
135                           Entropy : in OAEP_Block;
136                           Output  : out OAEP_Block) is
137     M00    : OAEP_HALF;
138     R      : OAEP_HALF;
139     HashR  : OAEP_HALF;
140     X      : OAEP_HALF;
141     HashX  : OAEP_HALF;
142     Y      : OAEP_HALF;
143     MsgLen : Natural;
144     MaxLen : Natural;
145     PadLen : Natural;
146     TMSR   : constant String := "TMSR-RSA";
147   begin
148     -- calculate maximum length of msg and needed amount of padding
149     -- make sure also that only MaxLen octets at most are used from Msg
150     MaxLen := OAEP_HALF_OCTETS - TMSR'Length - 3;  -- maximum msg that fits
151     MsgLen := Msg'Length;                          -- real msg length
152     if MsgLen > MaxLen then
153       MsgLen := MaxLen;  --only first MaxLen octets will be considered
154       PadLen := 0;       --no padding needed
155     else
156       PadLen := MaxLen - MsgLen; -- msg is potentially too short, add padding
157     end if;
158 
159     -- step 1: header and format to obtain M00
160       -- first octet is random bits
161     M00( M00'First ) := Entropy( Entropy'First );
162 
163       -- next 2 octets hold the used length of Msg (number of octets)
164     M00( M00'First + 2) := Character'Val( ( MsgLen * 8 ) mod 255 );
165     M00( M00'First + 1) := Character'Val( ( (MsgLen * 8 ) / 255 ) mod 255 );
166 
167       -- next 8 octets are reserved for later use, currently "TMSR-RSA"
168     M00( M00'First + 3 .. M00'First + 10 ) := TMSR;
169 
170       -- random bits for padding, if Msg is less than 245 octets
171     for I in 1 .. PadLen loop
172       M00( M00'First + 10 + I ) := Entropy( Entropy'First + I );
173     end loop;
174 
175       -- the message itself
176     M00( M00'Last - MsgLen + 1 .. M00'Last ) := 
177                                Msg( Msg'First .. Msg'First + MsgLen - 1 );
178 
179     -- step 2: R = OAEP_HALF_OCTETS random octets
180     -- can take LAST octets from given entropy as they are NOT used before
181     -- (even if original message was empty, padding uses at most half - 10
182     --   while entropy has full block length)
183     R := Entropy( Entropy'Last - OAEP_HALF_OCTETS + 1 .. Entropy'Last );
184 
185     -- step 3: X = M00 xor hash(R)
186     HashKeccak( R, HashR );
187     XOR_Strings( M00, HashR, X );
188 
189     -- step 4: Y = R xor hash(X)
190     HashKeccak( X, HashX );
191     XOR_Strings( R, HashX, Y );
192 
193     -- step 5: Output is X || Y
194     Output( Output'First .. Output'First + X'Length - 1 ) := X;
195     Output( Output'Last - Y'Length + 1 .. Output'Last )   := Y;
196     
197   end OAEP_Encrypt;
198 
199   procedure OAEP_Decrypt( Encr    : in OAEP_Block;
200                           Len     : out Natural;
201                           Output  : out OAEP_HALF;
202                           Success : out Boolean ) is
203     X, Y, M, R   : OAEP_HALF;
204     HashX, HashR : OAEP_HALF;
205     MaxLen       : constant Natural := OAEP_LENGTH_OCTETS - 11;
206     LenOctets    : Natural;
207   begin
208     -- step 1: separate X and Y
209     X := Encr( Encr'First .. Encr'First + X'Length - 1 );
210     Y := Encr( Encr'Last - Y'Length + 1 .. Encr'Last );
211 
212     -- step 2: R = Y xor hash(X)
213     HashKeccak( X, HashX );
214     XOR_Strings( Y, HashX, R );
215 
216     -- step 3: M = X xor hash(R)
217     HashKeccak( R, HashR );
218     XOR_Strings( X, HashR, M );
219 
220     -- step 4: extract length and message
221     Len := Character'Pos( M( M'First + 1 ) ) * 255 +
222            Character'Pos( M( M'First + 2 ) );
223     LenOctets := Len / 8; 
224 
225     if LenOctets > MaxLen or LenOctets < 0 then
226       Success := False;  -- error, failed to retrieve message
227     else
228       Success := True;
229       Output( Output'First .. Output'First + LenOctets - 1 ) := 
230         M( M'Last - LenOctets + 1 .. M'Last );
231     end if;
232 
233   end OAEP_Decrypt;
234 
235   -- helper method, xor on strings
236   -- NB: only Output'Length bits will be considered from S1 and S2
237   -- NB: caller is responsible for S1 and S2 being long enough!
238   procedure XOR_Strings( S1: in String; S2: in String; Output: out String ) is
239     V1, V2: Unsigned_8;
240   begin
241     for I in Output'Range loop
242       V1 := Character'Pos( S1( I ) );
243       V2 := Character'Pos( S2( I ) );
244       Output( I ) := Character'Val( V1 xor V2 );
245     end loop;
246   end XOR_Strings;
247 
248 
249 end SMG_OAEP;
-(0 . 0)(1 . 90)
254 -- Implementation of TMSR's OAEP with Keccak as hash function
255 --
256 -- S.MG, 2018
257 
258 with SMG_Keccak; use SMG_Keccak; -- Keccak is used as hash function
259 with Interfaces; use Interfaces; -- for Unsigned_8 type and bit-level ops
260 with Interfaces.C; use Interfaces.C; -- for interop with C
261 
262 package SMG_OAEP is
263   pragma Pure( SMG_OAEP ); -- stateless, no side effects -> can cache calls
264 
265   -- fixed length of OAEP block in bits and in octets
266   OAEP_LENGTH_BITS   : constant := 4096;
267   OAEP_LENGTH_OCTETS : constant := 512;
268   OAEP_HALF_OCTETS   : constant := OAEP_LENGTH_OCTETS / 2;
269 
270   -- subtypes used by the OAEP encrypt/decrypt
271   subtype OAEP_Block is String( 1 .. OAEP_LENGTH_OCTETS );
272   subtype OAEP_HALF is String( 1 .. OAEP_HALF_OCTETS );
273 
274   -- padding & formatting of maximum 1960 bits of the given String 
275   -- uses TMSR's OAEP schema:
276   -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message
277   --    where sz1 and sz2 store the length of the message in bits
278   --    the random octets before message are padding to make OAEP_LENGTH_OCTETS
279   -- 2. R = OAEP_HALF_OCTETS random bits
280   -- 3. X = M00 xor hash(R)
281   -- 4. Y = R xor hash(X)
282   -- 5. Result is X || Y 
283   -- NB: the Entropy parameter should be random octets from which this method 
284   -- will use as many as required for the OAEP encryption of given Msg
285   -- NB: at MOST OAEP_LENGTH_OCTETS - 11 octets of Msg! (Msg at most 1960 bits)
286   procedure OAEP_Encrypt( Msg     : in String;
287                           Entropy : in OAEP_Block;
288                           Output  : out OAEP_Block);
289 
290   -- This is the opposite of OAEP_Encrypt above.
291   -- @param Encr - an OAEP block previously obtained from OAEP_Encrypt
292   -- @param Len - this will hold the length of the obtained message (in bits!)
293   -- @param Output - the first Len octets of this are the recovered message
294   -- @param Success - set to TRUE if message was recovered, false otherwise
295   -- NB: when Success is FALSE, both Len and Output have undefined values
296   procedure OAEP_Decrypt( Encr    : in OAEP_Block;
297                           Len     : out Natural;
298                           Output  : out OAEP_HALF;
299                           Success : out Boolean);
300 
301   -- helper method, xor on strings
302   -- NB: only Output'Length bits will be considered from S1 and S2
303   -- NB: caller is responsible for S1 and S2 being long enough!
304   procedure XOR_Strings( S1: in String; S2: in String; Output: out String );
305 
306   -- gnat-specific methods for bit-level operations
307 	function Shift_Right( Value  : Unsigned_8; 
308                         Amount : Natural ) 
309                         return Unsigned_8;
310   pragma Import(Intrinsic, Shift_Right); 
311 
312 	function Shift_Left( Value  : Unsigned_8; 
313                         Amount : Natural ) 
314                         return Unsigned_8;
315   pragma Import(Intrinsic, Shift_Left); 
316 
317   -- conversions between bitstream and string
318   -- NB: caller has to ensure correct size of output parameter! no checks here.
319   procedure ToString( B: in Bitstream; S: out String );
320   procedure ToBitstream( S: in String; B: out Bitstream );
321 
322   -- public wrapper for Sponge to use String for input/output
323   procedure HashKeccak( Input     : in String;
324                         Output    : out String;
325                         Block_Len : in Keccak_Rate := Default_Bitrate);
326 
327   -- wrapper for calling from C
328   -- @param Input the input string, as array of characters (C style)
329   -- @param LenIn the length of the input string (as number of BITS)
330   -- @param LenOut the desired number of bits to be returned as output
331   -- @param Block_Len the bitrate used by the Keccak sponge (number of BITS)
332   -- @return an array of characters with first LenOut bits set to Keccak output
333 
334   -- NB: caller HAS TO provide the length of the Input (parameter LenIn)
335   -- NB: caller HAS TO provide the length of the Output (parameter LenOut)
336   function Hash( Input     : Interfaces.C.Char_Array;
337                  LenIn     : Interfaces.C.size_t;
338                  LenOut    : Interfaces.C.size_t;
339                  Block_Len : Interfaces.C.int := Default_Bitrate)
340                  return Interfaces.C.Char_Array;
341   pragma Export( C, Hash, "hash" );
342 
343 end SMG_OAEP;
- F90807132CF1AD922F6B901A4CD35190646BAAD554E0CBAE71C570909AF0025260DED9BD163657917AF4B08F5B29AEB704076D4F5949D8F6B1D14F60C837800B(1 . 3)(1 . 4)
348 with SMG_OAEP; use SMG_OAEP;
349 with SMG_Keccak; use SMG_Keccak;
350 with Ada.Exceptions; use Ada.Exceptions;
351 with Ada.Text_IO; use Ada.Text_IO;
(268 . 7)(269 . 7)
353 HexString : String( 1 .. ExpHex'Length );
354 begin
355 Put_Line("---sponge test---");
356 Sponge(Input, Bitrate, Output);
357 Sponge(Input, Output, Bitrate);
358 Put_Line("Input is:");
359 for I of Input loop
360 Put(Bit'Image(I));
(314 . 6)(315 . 123)
362 end if;
363 end test_keccak_function;
364
365 procedure test_bitstream_conversion is
366 S: String := "Aa*/";
367 E: Bitstream( 0 .. 31 ) := (1, 0, 0, 0, 0, 0, 1, 0,
368 1, 0, 0, 0, 0, 1, 1, 0,
369 0, 1, 0, 1, 0, 1, 0, 0,
370 1, 1, 1, 1, 0, 1, 0, 0);
371 B: Bitstream( 0 .. 31 );
372 SS: String := " t ";
373 begin
374 Put_Line("---Testing string to bitstream conversion---");
375 ToBitstream( S, B );
376 if E /= B then
377 Put_Line("FAILED: string to bitstream conversion.");
378 else
379 Put_Line("PASSED: string to bitstream conversion.");
380 end if;
381
382 Put_Line("---Testing bitstream to string conversion---");
383 ToString( B, SS );
384 if SS /= S then
385 Put_Line("FAILED: bitstream to string conversion");
386 Put_Line("EXPECTED: " & S);
387 Put_Line("OUTPUT: " & SS);
388 else
389 Put_Line("PASSED: bitstream to string conversion");
390 end if;
391 end test_bitstream_conversion;
392
393 procedure test_hash_keccak is
394 S: String := "X";
395 O: String := "abc";
396 B: Bitstream( 0 .. 23 );
397 BB: Bitstream( 1.. 8):= (0, 0, 0, 1, 1, 0, 1, 0);
398 Exp: Bitstream( 0 .. 23 ) := (1, 1, 1, 0, 0, 0, 0, 1,
399 0, 1, 1, 0, 0, 0, 1, 0,
400 1, 1, 1, 0, 0, 0, 1, 1);
401 begin
402 Put_Line("----Testing hash keccak on string " & S & "----");
403 HashKeccak(S, O);
404 Put_Line("OUTPUT: " & O);
405 ToBitstream( O, B );
406 if B /= Exp then
407 Put_Line("FAILED: testing hash keccak on string");
408 Put_Line("Output:");
409 for I of B loop
410 Put( Bit'Image( I ) );
411 end loop;
412 new_line(1);
413 Put_Line("Expected:");
414 for I of Exp loop
415 Put( Bit'Image( I ) );
416 end loop;
417 else
418 Put_Line("PASSED: testing hash keccak on string");
419 end if;
420 new_line(1);
421 end test_hash_keccak;
422
423 procedure test_xor_strings is
424 S1 : String := "ABC";
425 S2 : String := "CBA";
426 Exp : String := "...";
427 Result : String := "...";
428 begin
429 Exp( Exp'First ) := Character'Val( 2 );
430 Exp( Exp'First + 1 ) := Character'Val( 0 );
431 Exp( Exp'First + 2 ) := Character'Val( 2 );
432
433 Put_Line("----Testing xor on strings---");
434 XOR_Strings( S1, S2, Result);
435 Put_Line("S1 is " & S1);
436 Put_Line("S2 is " & S2);
437 Put_Line("S1 xor S2 is " & Result);
438 Put_Line("Result is: ");
439 for C of Result loop
440 Put( Natural'Image( Character'Pos( C ) ) );
441 end loop;
442 new_line(1);
443
444 if Result /= Exp then
445 Put_Line("FAILED: xor on strings");
446 else
447 Put_Line("PASSED: xor on strings");
448 end if;
449 end test_xor_strings;
450
451 procedure test_oaep is
452 Msg : String := "abcdefghij jihgfedcba123456789";
453 Encr : OAEP_Block := ( others => ' ' );
454 Decr : OAEP_HALF := ( others => ' ' );
455 Entropy : OAEP_Block := ( others => 'e' );
456 Len : Natural;
457 Flag : Boolean;
458 begin
459 Put_Line("----Testing OAEP Encrypt----");
460 OAEP_Encrypt( Msg, Entropy, Encr );
461
462 Put_Line("----Testing OAEP Decrypt----");
463 OAEP_Decrypt( Encr, Len, Decr, Flag );
464
465 Put_Line("Msg is: " & Msg);
466 Put_Line("Encr is: " & Encr);
467 Put_Line("Decr is: " & Decr);
468 Put_Line("Flag is: " & Boolean'Image( Flag ) );
469 Put_Line("Len is: " & Natural'Image( Len ) );
470
471 if Flag = False or
472 Len /= Msg'Length * 8 or
473 Decr( Decr'First .. Decr'First + Msg'Length - 1 ) /= Msg
474 then
475 Put_Line("FAILED: oaep test");
476 else
477 Put_Line("PASSED: oaep test");
478 end if;
479
480 end test_oaep;
481
482 -- end of helper methods
483
484 --variables
(354 . 4)(472 . 16)
486 -- test flipping octets
487 test_flip;
488
489 -- test bitstream conversion
490 test_bitstream_conversion;
491
492 -- test hash keccak (strings version)
493 test_hash_keccak;
494
495 -- test oaep encrypt + decrypt
496 test_oaep;
497
498 -- test xor on strings
499 test_xor_strings;
500
501 end SMG_Keccak.Test;