raw
eucrypt_ch10_oaep...    1 -- S.MG, 2018
eucrypt_ch10_oaep... 2
eucrypt_ch10_oaep... 3 package body SMG_OAEP is
eucrypt_ch10_oaep... 4
eucrypt_ch10_oaep... 5 procedure HashKeccak( Input : in String;
eucrypt_ch10_oaep... 6 Output : out String;
eucrypt_ch10_oaep... 7 Block_Len : in Keccak_Rate := Default_Bitrate) is
eucrypt_ch10_oaep... 8 BIn : Bitstream( 0 .. Input'Length * 8 - 1 );
eucrypt_ch10_oaep... 9 BOut : Bitstream( 0 .. Output'Length * 8 - 1 );
eucrypt_ch10_oaep... 10 begin
eucrypt_ch10_oaep... 11 ToBitstream( Input, BIn);
eucrypt_ch10_oaep... 12 Sponge( BIn, BOut, Block_Len);
eucrypt_ch10_oaep... 13 ToString( BOut, Output );
eucrypt_ch10_oaep... 14 end HashKeccak;
eucrypt_ch10_oaep... 15
eucrypt_ch10_oaep... 16 function Hash( Input : Interfaces.C.Char_Array;
eucrypt_ch10_oaep... 17 LenIn : Interfaces.C.size_t;
eucrypt_ch10_oaep... 18 LenOut : Interfaces.C.size_t;
eucrypt_ch10_oaep... 19 Block_Len : Interfaces.C.int := Default_Bitrate)
eucrypt_ch10_oaep... 20 return Interfaces.C.Char_Array is
eucrypt_ch10_oaep... 21 AdaLenIn : Natural := Natural(LenIn);
eucrypt_ch10_oaep... 22 AdaLenOut : Natural := Natural(LenOut);
eucrypt_ch10_oaep... 23 InStr : String( 0 .. AdaLenIn-1 ) := (others => '0');
eucrypt_ch10_oaep... 24 OutStr : String( 0 .. AdaLenOut-1 ) := (others => '0');
eucrypt_ch10_oaep... 25 COut : Interfaces.C.Char_Array( 0 .. LenOut-1 );
eucrypt_ch10_oaep... 26 Count : Natural := AdaLenOut;
eucrypt_ch10_oaep... 27 CCount : Interfaces.C.size_t := LenOut;
eucrypt_ch10_oaep... 28 begin
eucrypt_ch10_oaep... 29 Interfaces.C.To_Ada( Input, InStr, AdaLenIn );
eucrypt_ch10_oaep... 30 HashKeccak( InStr, OutStr, Keccak_Rate(Block_Len) );
eucrypt_ch10_oaep... 31 Interfaces.C.To_C( OutStr, COut, CCount );
eucrypt_ch10_oaep... 32 return COut;
eucrypt_ch10_oaep... 33 end Hash;
eucrypt_ch10_oaep... 34
eucrypt_ch10_oaep... 35 -- conversion between types
eucrypt_ch10_oaep... 36 procedure ToString(B: in Bitstream; S: out String ) is
eucrypt_ch10_oaep... 37 N : Natural;
eucrypt_ch10_oaep... 38 Pos : Natural;
eucrypt_ch10_oaep... 39 begin
eucrypt_ch10_oaep... 40 Pos := B'First;
eucrypt_ch10_oaep... 41 for I in S'Range loop
eucrypt_ch10_oaep... 42 N := Natural( B( Pos ) ) +
eucrypt_ch10_oaep... 43 Natural( B( Pos + 1 ) ) * 2 +
eucrypt_ch10_oaep... 44 Natural( B( Pos + 2 ) ) * 4 +
eucrypt_ch10_oaep... 45 Natural( B( Pos + 3 ) ) * 8 +
eucrypt_ch10_oaep... 46 Natural( B( Pos + 4 ) ) * 16 +
eucrypt_ch10_oaep... 47 Natural( B( Pos + 5 ) ) * 32 +
eucrypt_ch10_oaep... 48 Natural( B( Pos + 6 ) ) * 64 +
eucrypt_ch10_oaep... 49 Natural( B( Pos + 7 ) ) * 128;
eucrypt_ch10_oaep... 50 Pos := Pos + 8;
eucrypt_ch10_oaep... 51 S( I ) := Character'Val( N );
eucrypt_ch10_oaep... 52 end loop;
eucrypt_ch10_oaep... 53 end ToString;
eucrypt_ch10_oaep... 54
eucrypt_ch10_oaep... 55 procedure ToBitstream(S: in String; B: out Bitstream ) is
eucrypt_ch10_oaep... 56 V : Unsigned_8;
eucrypt_ch10_oaep... 57 Pos : Natural;
eucrypt_ch10_oaep... 58 begin
eucrypt_ch10_oaep... 59 Pos := B'First;
eucrypt_ch10_oaep... 60 for C of S loop
eucrypt_ch10_oaep... 61 V := Character'Pos( C );
eucrypt_ch10_oaep... 62 B( Pos ) := Bit( V and 1 );
eucrypt_ch10_oaep... 63 B( Pos + 1 ) := Bit( Shift_Right( V, 1 ) and 1 );
eucrypt_ch10_oaep... 64 B( Pos + 2 ) := Bit( Shift_Right( V, 2 ) and 1 );
eucrypt_ch10_oaep... 65 B( Pos + 3 ) := Bit( Shift_Right( V, 3 ) and 1 );
eucrypt_ch10_oaep... 66 B( Pos + 4 ) := Bit( Shift_Right( V, 4 ) and 1 );
eucrypt_ch10_oaep... 67 B( Pos + 5 ) := Bit( Shift_Right( V, 5 ) and 1 );
eucrypt_ch10_oaep... 68 B( Pos + 6 ) := Bit( Shift_Right( V, 6 ) and 1 );
eucrypt_ch10_oaep... 69 B( Pos + 7 ) := Bit( Shift_Right( V, 7 ) and 1 );
eucrypt_ch10_oaep... 70
eucrypt_ch10_oaep... 71 Pos := Pos + 8;
eucrypt_ch10_oaep... 72 end loop;
eucrypt_ch10_oaep... 73 end ToBitstream;
eucrypt_ch10_oaep... 74
eucrypt_ch10_oaep... 75 -- padding & formatting of maximum 1960 bits of the given String
eucrypt_ch10_oaep... 76 -- uses TMSR's OAEP schema:
eucrypt_ch10_oaep... 77 -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message
eucrypt_ch10_oaep... 78 -- where sz1 and sz2 store the length of the message in bits
eucrypt_ch10_oaep... 79 -- the random octets before message are padding to make OAEP_LENGTH_OCTETS
eucrypt_ch10_oaep... 80 -- 2. R = OAEP_HALF_OCTETS random bits
eucrypt_ch10_oaep... 81 -- 3. X = M00 xor hash(R)
eucrypt_ch10_oaep... 82 -- 4. Y = R xor hash(X)
eucrypt_ch10_oaep... 83 -- 5. Result is X || Y
eucrypt_ch10_oaep... 84 -- NB: the Entropy parameter should be random octets from which this method
eucrypt_ch10_oaep... 85 -- will use as many as required for the OAEP encryption of given Msg
eucrypt_ch10_oaep... 86 -- NB: at MOST OAEP_LENGTH_OCTETS - 11 octets of Msg! (Msg at most 1960 bits)
eucrypt_ch10_oaep... 87 procedure OAEP_Encrypt( Msg : in String;
eucrypt_ch10_oaep... 88 Entropy : in OAEP_Block;
eucrypt_ch10_oaep... 89 Output : out OAEP_Block) is
eucrypt_ch10_oaep... 90 M00 : OAEP_HALF;
eucrypt_ch10_oaep... 91 R : OAEP_HALF;
eucrypt_ch10_oaep... 92 HashR : OAEP_HALF;
eucrypt_ch10_oaep... 93 X : OAEP_HALF;
eucrypt_ch10_oaep... 94 HashX : OAEP_HALF;
eucrypt_ch10_oaep... 95 Y : OAEP_HALF;
eucrypt_ch10_oaep... 96 MsgLen : Natural;
eucrypt_ch10_oaep... 97 MaxLen : Natural;
eucrypt_ch10_oaep... 98 PadLen : Natural;
eucrypt_ch10_oaep... 99 TMSR : constant String := "TMSR-RSA";
eucrypt_ch10_oaep... 100 begin
eucrypt_ch10_oaep... 101 -- calculate maximum length of msg and needed amount of padding
eucrypt_ch10_oaep... 102 -- make sure also that only MaxLen octets at most are used from Msg
eucrypt_ch10_oaep... 103 MaxLen := OAEP_HALF_OCTETS - TMSR'Length - 3; -- maximum msg that fits
eucrypt_ch10_oaep... 104 MsgLen := Msg'Length; -- real msg length
eucrypt_ch10_oaep... 105 if MsgLen > MaxLen then
eucrypt_ch10_oaep... 106 MsgLen := MaxLen; --only first MaxLen octets will be considered
eucrypt_ch10_oaep... 107 PadLen := 0; --no padding needed
eucrypt_ch10_oaep... 108 else
eucrypt_ch10_oaep... 109 PadLen := MaxLen - MsgLen; -- msg is potentially too short, add padding
eucrypt_ch10_oaep... 110 end if;
eucrypt_ch10_oaep... 111
eucrypt_ch10_oaep... 112 -- step 1: header and format to obtain M00
eucrypt_ch10_oaep... 113 -- first octet is random bits
eucrypt_ch10_oaep... 114 M00( M00'First ) := Entropy( Entropy'First );
eucrypt_ch10_oaep... 115
eucrypt_ch10_oaep... 116 -- next 2 octets hold the used length of Msg (number of octets)
eucrypt_ch10_oaep... 117 M00( M00'First + 2) := Character'Val( ( MsgLen * 8 ) mod 255 );
eucrypt_ch10_oaep... 118 M00( M00'First + 1) := Character'Val( ( (MsgLen * 8 ) / 255 ) mod 255 );
eucrypt_ch10_oaep... 119
eucrypt_ch10_oaep... 120 -- next 8 octets are reserved for later use, currently "TMSR-RSA"
eucrypt_ch10_oaep... 121 M00( M00'First + 3 .. M00'First + 10 ) := TMSR;
eucrypt_ch10_oaep... 122
eucrypt_ch10_oaep... 123 -- random bits for padding, if Msg is less than 245 octets
eucrypt_ch10_oaep... 124 for I in 1 .. PadLen loop
eucrypt_ch10_oaep... 125 M00( M00'First + 10 + I ) := Entropy( Entropy'First + I );
eucrypt_ch10_oaep... 126 end loop;
eucrypt_ch10_oaep... 127
eucrypt_ch10_oaep... 128 -- the message itself
eucrypt_ch10_oaep... 129 M00( M00'Last - MsgLen + 1 .. M00'Last ) :=
eucrypt_ch10_oaep... 130 Msg( Msg'First .. Msg'First + MsgLen - 1 );
eucrypt_ch10_oaep... 131
eucrypt_ch10_oaep... 132 -- step 2: R = OAEP_HALF_OCTETS random octets
eucrypt_ch10_oaep... 133 -- can take LAST octets from given entropy as they are NOT used before
eucrypt_ch10_oaep... 134 -- (even if original message was empty, padding uses at most half - 10
eucrypt_ch10_oaep... 135 -- while entropy has full block length)
eucrypt_ch10_oaep... 136 R := Entropy( Entropy'Last - OAEP_HALF_OCTETS + 1 .. Entropy'Last );
eucrypt_ch10_oaep... 137
eucrypt_ch10_oaep... 138 -- step 3: X = M00 xor hash(R)
eucrypt_ch10_oaep... 139 HashKeccak( R, HashR );
eucrypt_ch10_oaep... 140 XOR_Strings( M00, HashR, X );
eucrypt_ch10_oaep... 141
eucrypt_ch10_oaep... 142 -- step 4: Y = R xor hash(X)
eucrypt_ch10_oaep... 143 HashKeccak( X, HashX );
eucrypt_ch10_oaep... 144 XOR_Strings( R, HashX, Y );
eucrypt_ch10_oaep... 145
eucrypt_ch10_oaep... 146 -- step 5: Output is X || Y
eucrypt_ch10_oaep... 147 Output( Output'First .. Output'First + X'Length - 1 ) := X;
eucrypt_ch10_oaep... 148 Output( Output'Last - Y'Length + 1 .. Output'Last ) := Y;
eucrypt_ch10_oaep... 149
eucrypt_ch10_oaep... 150 end OAEP_Encrypt;
eucrypt_ch10_oaep... 151
eucrypt_ch10_oaep... 152 procedure OAEP_Decrypt( Encr : in OAEP_Block;
eucrypt_ch10_oaep... 153 Len : out Natural;
eucrypt_ch10_oaep... 154 Output : out OAEP_HALF;
eucrypt_ch10_oaep... 155 Success : out Boolean ) is
eucrypt_ch10_oaep... 156 X, Y, M, R : OAEP_HALF;
eucrypt_ch10_oaep... 157 HashX, HashR : OAEP_HALF;
eucrypt_ch10_oaep... 158 MaxLen : constant Natural := OAEP_LENGTH_OCTETS - 11;
eucrypt_ch10_oaep... 159 LenOctets : Natural;
eucrypt_ch10_oaep... 160 begin
eucrypt_ch10_oaep... 161 -- step 1: separate X and Y
eucrypt_ch10_oaep... 162 X := Encr( Encr'First .. Encr'First + X'Length - 1 );
eucrypt_ch10_oaep... 163 Y := Encr( Encr'Last - Y'Length + 1 .. Encr'Last );
eucrypt_ch10_oaep... 164
eucrypt_ch10_oaep... 165 -- step 2: R = Y xor hash(X)
eucrypt_ch10_oaep... 166 HashKeccak( X, HashX );
eucrypt_ch10_oaep... 167 XOR_Strings( Y, HashX, R );
eucrypt_ch10_oaep... 168
eucrypt_ch10_oaep... 169 -- step 3: M = X xor hash(R)
eucrypt_ch10_oaep... 170 HashKeccak( R, HashR );
eucrypt_ch10_oaep... 171 XOR_Strings( X, HashR, M );
eucrypt_ch10_oaep... 172
eucrypt_ch10_oaep... 173 -- step 4: extract length and message
eucrypt_ch10_oaep... 174 Len := Character'Pos( M( M'First + 1 ) ) * 255 +
eucrypt_ch10_oaep... 175 Character'Pos( M( M'First + 2 ) );
eucrypt_ch10_oaep... 176 LenOctets := Len / 8;
eucrypt_ch10_oaep... 177
eucrypt_ch10_oaep... 178 if LenOctets > MaxLen or LenOctets < 0 then
eucrypt_ch10_oaep... 179 Success := False; -- error, failed to retrieve message
eucrypt_ch10_oaep... 180 else
eucrypt_ch10_oaep... 181 Success := True;
eucrypt_ch10_oaep... 182 Output( Output'First .. Output'First + LenOctets - 1 ) :=
eucrypt_ch10_oaep... 183 M( M'Last - LenOctets + 1 .. M'Last );
eucrypt_ch10_oaep... 184 end if;
eucrypt_ch10_oaep... 185
eucrypt_ch10_oaep... 186 end OAEP_Decrypt;
eucrypt_ch10_oaep... 187
eucrypt_ch10_oaep... 188 -- helper method, xor on strings
eucrypt_ch10_oaep... 189 -- NB: only Output'Length bits will be considered from S1 and S2
eucrypt_ch10_oaep... 190 -- NB: caller is responsible for S1 and S2 being long enough!
eucrypt_ch10_oaep... 191 procedure XOR_Strings( S1: in String; S2: in String; Output: out String ) is
eucrypt_ch10_oaep... 192 V1, V2: Unsigned_8;
eucrypt_ch10_oaep... 193 begin
eucrypt_ch10_oaep... 194 for I in Output'Range loop
eucrypt_ch10_oaep... 195 V1 := Character'Pos( S1( I ) );
eucrypt_ch10_oaep... 196 V2 := Character'Pos( S2( I ) );
eucrypt_ch10_oaep... 197 Output( I ) := Character'Val( V1 xor V2 );
eucrypt_ch10_oaep... 198 end loop;
eucrypt_ch10_oaep... 199 end XOR_Strings;
eucrypt_ch10_oaep... 200
eucrypt_ch10_oaep... 201
eucrypt_ch10_oaep... 202 end SMG_OAEP;