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