raw
smg_comms_rsa_oaep      1  -- S.MG, 2018
smg_comms_rsa_oaep 2
smg_comms_rsa_oaep 3 with Interfaces; use Interfaces;
smg_comms_rsa_oaep 4 with OAEP;
smg_comms_rsa_oaep 5 with RNG;
smg_comms_rsa_oaep 6
smg_comms_rsa_oaep 7 package body RSA_OAEP is
smg_comms_rsa_oaep 8
smg_comms_rsa_oaep 9 -- OAEP + RSA with given public key.
smg_comms_rsa_oaep 10 -- Steps:
smg_comms_rsa_oaep 11 -- 1. repeat oaep.encrypt of Plain
smg_comms_rsa_oaep 12 -- until the result has first octet < than first octet of Key's modulus.
smg_comms_rsa_oaep 13 -- 2. RSA.encrypt with Key on the result from 1.
smg_comms_rsa_oaep 14 procedure Encrypt( Plain: in Raw_Types.Octets;
smg_comms_rsa_oaep 15 Key : in RSA_pkey;
smg_comms_rsa_oaep 16 Encr : out Raw_Types.RSA_len ) is
smg_comms_rsa_oaep 17 -- block obtained through OAEP padding of given input Plain
smg_comms_rsa_oaep 18 Blk : OAEP.OAEP_Block := ( others => 0 );
smg_comms_rsa_oaep 19 Entropy : OAEP.OAEP_Block;
smg_comms_rsa_oaep 20 Len : constant Natural := entropy'Length;
smg_comms_rsa_oaep 21 begin
smg_comms_rsa_oaep 22 -- loop cond: 1st octet of oaep block is < 1st octet of key's modulus
smg_comms_rsa_oaep 23 loop
smg_comms_rsa_oaep 24 -- get random bits via RNG (FG)
smg_comms_rsa_oaep 25 RNG.Get_Octets( Entropy );
smg_comms_rsa_oaep 26
smg_comms_rsa_oaep 27 -- oaep encrypt
smg_comms_rsa_oaep 28 OAEP.OAEP_Encrypt( Plain, Entropy, Blk );
smg_comms_rsa_oaep 29
smg_comms_rsa_oaep 30 -- check that the oaep block is suitable i.e. comparison of 1st octet
smg_comms_rsa_oaep 31 if Blk(Blk'First) < Key.n(Key.n'First) then exit; end if;
smg_comms_rsa_oaep 32
smg_comms_rsa_oaep 33 end loop; -- oaep block < modulus
smg_comms_rsa_oaep 34
smg_comms_rsa_oaep 35 -- RSA encrypt
smg_comms_rsa_oaep 36 Public_RSA( Blk, Key, Encr );
smg_comms_rsa_oaep 37 end; --Encrypt (OAEP+RSA)
smg_comms_rsa_oaep 38
smg_comms_rsa_oaep 39 -- RSA+OAEP Decrypt
smg_comms_rsa_oaep 40 -- Steps:
smg_comms_rsa_oaep 41 -- 1. RSA Decrypt (secret key)
smg_comms_rsa_oaep 42 -- 2. OAEP Decrypt
smg_comms_rsa_oaep 43 procedure Decrypt( Encr : in Raw_Types.RSA_len;
smg_comms_rsa_oaep 44 Key : in RSA_skey;
smg_comms_rsa_oaep 45 Plain: out Raw_Types.Octets;
smg_comms_rsa_oaep 46 Plain_Len: out Natural;
smg_comms_rsa_oaep 47 Success: out Boolean) is
smg_comms_rsa_oaep 48 Blk : OAEP.OAEP_Block;
smg_comms_rsa_oaep 49 Msg : OAEP.OAEP_HALF;
smg_comms_rsa_oaep 50 Msg_Len : Natural;
smg_comms_rsa_oaep 51 begin
smg_comms_rsa_oaep 52 -- RSA decrypt with provided secret key
smg_comms_rsa_oaep 53 -- NB: result HAS TO BE AN OAEP BLOCK HERE! Even if - potentially - 0 led!
smg_comms_rsa_oaep 54 Private_RSA( Encr, Key, Blk );
smg_comms_rsa_oaep 55
smg_comms_rsa_oaep 56 -- OAEP decrypt
smg_comms_rsa_oaep 57 OAEP.OAEP_Decrypt(Blk, Msg_Len, Msg, Success);
smg_comms_rsa_oaep 58 -- switch to Length in OCTETS!
smg_comms_rsa_oaep 59 Msg_Len := Msg_Len / 8;
smg_comms_rsa_oaep 60
smg_comms_rsa_oaep 61 -- check that result FITS in given output array - otherwise, fail
smg_comms_rsa_oaep 62 if Msg_Len > Plain'Length then
smg_comms_rsa_oaep 63 Success := FALSE;
smg_comms_rsa_oaep 64 Plain_Len := Msg_Len; --to give a clue to caller
smg_comms_rsa_oaep 65 else
smg_comms_rsa_oaep 66 Plain_Len := Msg_Len;
smg_comms_rsa_oaep 67 Plain( Plain'First ..
smg_comms_rsa_oaep 68 Plain'First + Plain_Len-1) := Msg( Msg'First ..
smg_comms_rsa_oaep 69 Msg'First + Plain_Len -1 );
smg_comms_rsa_oaep 70 end if;
smg_comms_rsa_oaep 71 end Decrypt;
smg_comms_rsa_oaep 72
smg_comms_rsa_oaep 73 -- helper methods
smg_comms_rsa_oaep 74 -- encrypt with public RSA key given as struct, Ada style
smg_comms_rsa_oaep 75 procedure Public_RSA( Plain: in Raw_Types.Octets;
smg_comms_rsa_oaep 76 Key : in RSA_pkey;
smg_comms_rsa_oaep 77 Encr : out Raw_Types.RSA_len) is
smg_comms_rsa_oaep 78 Encr_char : char_array( size_t(Encr'First) .. size_t(Encr'Last));
smg_comms_rsa_oaep 79 Plain_char : char_array( size_t(Plain'First) .. size_t(Plain'Last));
smg_comms_rsa_oaep 80 N_char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last));
smg_comms_rsa_oaep 81 E_char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last));
smg_comms_rsa_oaep 82 out_len : Integer;
smg_comms_rsa_oaep 83 begin
smg_comms_rsa_oaep 84 -- convert to char array
smg_comms_rsa_oaep 85 Octets_To_Char_Array( Plain, Plain_char );
smg_comms_rsa_oaep 86 Octets_To_Char_Array( Key.n, N_char );
smg_comms_rsa_oaep 87 Octets_To_Char_Array( Key.e, E_char );
smg_comms_rsa_oaep 88 -- call C imported function
smg_comms_rsa_oaep 89 out_len := Public_RSA_C( Encr_char , Encr'Length,
smg_comms_rsa_oaep 90 Plain_char , Plain'Length,
smg_comms_rsa_oaep 91 N_char , Key.n'Length,
smg_comms_rsa_oaep 92 E_char , Key.e'Length);
smg_comms_rsa_oaep 93 -- convert back to octets
smg_comms_rsa_oaep 94 Char_Array_To_Octets( Encr_char, Encr );
smg_comms_rsa_oaep 95 -- C code trims leading 0s -> need to move octets if out_len<Encr'Length
smg_comms_rsa_oaep 96 if out_len < Encr'Length then
smg_comms_rsa_oaep 97 Encr(Encr'Last - out_len + 1 .. Encr'Last) := Encr(Encr'First ..
smg_comms_rsa_oaep 98 Encr'First+out_len-1);
smg_comms_rsa_oaep 99 Encr(Encr'First .. Encr'Last-out_len) := (others=>0);
smg_comms_rsa_oaep 100 end if;
smg_comms_rsa_oaep 101 -- no need to return anything!
smg_comms_rsa_oaep 102 end Public_RSA;
smg_comms_rsa_oaep 103
smg_comms_rsa_oaep 104 procedure Private_RSA( Encr : in Raw_Types.RSA_len;
smg_comms_rsa_oaep 105 Key : in RSA_skey;
smg_comms_rsa_oaep 106 Plain : out Raw_Types.Octets) is
smg_comms_rsa_oaep 107 Plain_Char : char_array( size_t(Plain'First) .. size_t(Plain'Last) );
smg_comms_rsa_oaep 108 Plain_Len : Integer;
smg_comms_rsa_oaep 109 Encr_Char : char_array( size_t(Encr'First) .. size_t(Encr'Last) );
smg_comms_rsa_oaep 110 N_Char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last) );
smg_comms_rsa_oaep 111 E_Char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last) );
smg_comms_rsa_oaep 112 D_Char : char_array( size_t(Key.d'First) .. size_t(Key.d'Last) );
smg_comms_rsa_oaep 113 P_Char : char_array( size_t(Key.p'First) .. size_t(Key.p'Last) );
smg_comms_rsa_oaep 114 Q_Char : char_array( size_t(Key.q'First) .. size_t(Key.q'Last) );
smg_comms_rsa_oaep 115 U_Char : char_array( size_t(Key.u'First) .. size_t(Key.u'Last) );
smg_comms_rsa_oaep 116 begin
smg_comms_rsa_oaep 117 -- convert key and encrypted message to C char_arrays
smg_comms_rsa_oaep 118 Octets_To_Char_Array( Encr, Encr_Char );
smg_comms_rsa_oaep 119 Octets_To_Char_Array( Key.n, N_Char );
smg_comms_rsa_oaep 120 Octets_To_Char_Array( Key.e, E_Char );
smg_comms_rsa_oaep 121 Octets_To_Char_Array( Key.d, D_Char );
smg_comms_rsa_oaep 122 Octets_To_Char_Array( Key.p, P_Char );
smg_comms_rsa_oaep 123 Octets_To_Char_Array( Key.q, Q_Char );
smg_comms_rsa_oaep 124 Octets_To_Char_Array( Key.u, U_Char );
smg_comms_rsa_oaep 125 -- call RSA decrypt via C_Wrappers
smg_comms_rsa_oaep 126 Plain_Len := Private_RSA_C( Plain_Char, Plain'Length,
smg_comms_rsa_oaep 127 Encr_Char , Encr'Length,
smg_comms_rsa_oaep 128 N_Char , Key.n'Length,
smg_comms_rsa_oaep 129 E_Char , Key.e'Length,
smg_comms_rsa_oaep 130 D_Char , Key.d'Length,
smg_comms_rsa_oaep 131 P_Char , Key.p'Length,
smg_comms_rsa_oaep 132 Q_Char , Key.q'Length,
smg_comms_rsa_oaep 133 U_Char , Key.u'Length);
smg_comms_rsa_oaep 134 -- convert result back to Octets
smg_comms_rsa_oaep 135 Char_Array_To_Octets( Plain_Char, Plain );
smg_comms_rsa_oaep 136 -- if length < OAEP_Block'Length,it's 0-led and got trimmed, so move it
smg_comms_rsa_oaep 137 if Plain_Len < Plain'Length then
smg_comms_rsa_oaep 138 Plain(Plain'Last-Plain_Len+1..Plain'Last):= Plain(Plain'First ..
smg_comms_rsa_oaep 139 Plain'First + Plain_Len -1);
smg_comms_rsa_oaep 140 Plain(Plain'First .. Plain'Last-Plain_Len) := (others => 0);
smg_comms_rsa_oaep 141 end if;
smg_comms_rsa_oaep 142 -- no need to return anything!
smg_comms_rsa_oaep 143 end Private_RSA;
smg_comms_rsa_oaep 144
smg_comms_rsa_oaep 145 procedure Octets_To_Char_Array( O : in Raw_Types.Octets;
smg_comms_rsa_oaep 146 A : out Interfaces.C.char_array) is
smg_comms_rsa_oaep 147 begin
smg_comms_rsa_oaep 148 -- check that lengths ARE THE SAME!
smg_comms_rsa_oaep 149 if A'Length /= O'Length then
smg_comms_rsa_oaep 150 raise Mismatched_Lengths_Error;
smg_comms_rsa_oaep 151 end if;
smg_comms_rsa_oaep 152 -- copy values over octet by octet
smg_comms_rsa_oaep 153 for I in 0 .. O'Length-1 loop
smg_comms_rsa_oaep 154 A( A'First + Interfaces.C.size_t( I )) :=
smg_comms_rsa_oaep 155 Interfaces.C.Char( Character'Val(O(O'First + I)));
smg_comms_rsa_oaep 156 end loop;
smg_comms_rsa_oaep 157 end Octets_To_Char_Array;
smg_comms_rsa_oaep 158
smg_comms_rsa_oaep 159 procedure Char_Array_To_Octets( A : in Interfaces.C.char_array;
smg_comms_rsa_oaep 160 O : out Raw_Types.Octets) is
smg_comms_rsa_oaep 161 begin
smg_comms_rsa_oaep 162 -- check that lengths ARE THE SAME!
smg_comms_rsa_oaep 163 if A'Length /= O'Length then
smg_comms_rsa_oaep 164 raise Mismatched_Lengths_Error;
smg_comms_rsa_oaep 165 end if;
smg_comms_rsa_oaep 166 -- copy values over octet by octet
smg_comms_rsa_oaep 167 for I in 0..O'Length -1 loop
smg_comms_rsa_oaep 168 O( O'First + I ) := Character'Pos( Character(
smg_comms_rsa_oaep 169 A( A'First + Interfaces.C.size_t( I )) ));
smg_comms_rsa_oaep 170 end loop;
smg_comms_rsa_oaep 171 end Char_Array_To_Octets;
smg_comms_rsa_oaep 172
smg_comms_rsa_oaep 173 end RSA_OAEP;