-
+ E2C22C3D60357595FA21ABFCF4535F455A3984272FD66AC9F36B14C263023C149AFBB7862B4C8D9516CFE0AA9200141E141539DB52906A09379BB92277B47529
smg_comms/src/rsa_oaep.adb
(0 . 0)(1 . 173)
1143 -- S.MG, 2018
1144
1145 with Interfaces; use Interfaces;
1146 with OAEP;
1147 with RNG;
1148
1149 package body RSA_OAEP is
1150
1151 -- OAEP + RSA with given public key.
1152 -- Steps:
1153 -- 1. repeat oaep.encrypt of Plain
1154 -- until the result has first octet < than first octet of Key's modulus.
1155 -- 2. RSA.encrypt with Key on the result from 1.
1156 procedure Encrypt( Plain: in Raw_Types.Octets;
1157 Key : in RSA_pkey;
1158 Encr : out Raw_Types.RSA_len ) is
1159 -- block obtained through OAEP padding of given input Plain
1160 Blk : OAEP.OAEP_Block := ( others => 0 );
1161 Entropy : OAEP.OAEP_Block;
1162 Len : constant Natural := entropy'Length;
1163 begin
1164 -- loop cond: 1st octet of oaep block is < 1st octet of key's modulus
1165 loop
1166 -- get random bits via RNG (FG)
1167 RNG.Get_Octets( Entropy );
1168
1169 -- oaep encrypt
1170 OAEP.OAEP_Encrypt( Plain, Entropy, Blk );
1171
1172 -- check that the oaep block is suitable i.e. comparison of 1st octet
1173 if Blk(Blk'First) < Key.n(Key.n'First) then exit; end if;
1174
1175 end loop; -- oaep block < modulus
1176
1177 -- RSA encrypt
1178 Public_RSA( Blk, Key, Encr );
1179 end; --Encrypt (OAEP+RSA)
1180
1181 -- RSA+OAEP Decrypt
1182 -- Steps:
1183 -- 1. RSA Decrypt (secret key)
1184 -- 2. OAEP Decrypt
1185 procedure Decrypt( Encr : in Raw_Types.RSA_len;
1186 Key : in RSA_skey;
1187 Plain: out Raw_Types.Octets;
1188 Plain_Len: out Natural;
1189 Success: out Boolean) is
1190 Blk : OAEP.OAEP_Block;
1191 Msg : OAEP.OAEP_HALF;
1192 Msg_Len : Natural;
1193 begin
1194 -- RSA decrypt with provided secret key
1195 -- NB: result HAS TO BE AN OAEP BLOCK HERE! Even if - potentially - 0 led!
1196 Private_RSA( Encr, Key, Blk );
1197
1198 -- OAEP decrypt
1199 OAEP.OAEP_Decrypt(Blk, Msg_Len, Msg, Success);
1200 -- switch to Length in OCTETS!
1201 Msg_Len := Msg_Len / 8;
1202
1203 -- check that result FITS in given output array - otherwise, fail
1204 if Msg_Len > Plain'Length then
1205 Success := FALSE;
1206 Plain_Len := Msg_Len; --to give a clue to caller
1207 else
1208 Plain_Len := Msg_Len;
1209 Plain( Plain'First ..
1210 Plain'First + Plain_Len-1) := Msg( Msg'First ..
1211 Msg'First + Plain_Len -1 );
1212 end if;
1213 end Decrypt;
1214
1215 -- helper methods
1216 -- encrypt with public RSA key given as struct, Ada style
1217 procedure Public_RSA( Plain: in Raw_Types.Octets;
1218 Key : in RSA_pkey;
1219 Encr : out Raw_Types.RSA_len) is
1220 Encr_char : char_array( size_t(Encr'First) .. size_t(Encr'Last));
1221 Plain_char : char_array( size_t(Plain'First) .. size_t(Plain'Last));
1222 N_char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last));
1223 E_char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last));
1224 out_len : Integer;
1225 begin
1226 -- convert to char array
1227 Octets_To_Char_Array( Plain, Plain_char );
1228 Octets_To_Char_Array( Key.n, N_char );
1229 Octets_To_Char_Array( Key.e, E_char );
1230 -- call C imported function
1231 out_len := Public_RSA_C( Encr_char , Encr'Length,
1232 Plain_char , Plain'Length,
1233 N_char , Key.n'Length,
1234 E_char , Key.e'Length);
1235 -- convert back to octets
1236 Char_Array_To_Octets( Encr_char, Encr );
1237 -- C code trims leading 0s -> need to move octets if out_len<Encr'Length
1238 if out_len < Encr'Length then
1239 Encr(Encr'Last - out_len + 1 .. Encr'Last) := Encr(Encr'First ..
1240 Encr'First+out_len-1);
1241 Encr(Encr'First .. Encr'Last-out_len) := (others=>0);
1242 end if;
1243 -- no need to return anything!
1244 end Public_RSA;
1245
1246 procedure Private_RSA( Encr : in Raw_Types.RSA_len;
1247 Key : in RSA_skey;
1248 Plain : out Raw_Types.Octets) is
1249 Plain_Char : char_array( size_t(Plain'First) .. size_t(Plain'Last) );
1250 Plain_Len : Integer;
1251 Encr_Char : char_array( size_t(Encr'First) .. size_t(Encr'Last) );
1252 N_Char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last) );
1253 E_Char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last) );
1254 D_Char : char_array( size_t(Key.d'First) .. size_t(Key.d'Last) );
1255 P_Char : char_array( size_t(Key.p'First) .. size_t(Key.p'Last) );
1256 Q_Char : char_array( size_t(Key.q'First) .. size_t(Key.q'Last) );
1257 U_Char : char_array( size_t(Key.u'First) .. size_t(Key.u'Last) );
1258 begin
1259 -- convert key and encrypted message to C char_arrays
1260 Octets_To_Char_Array( Encr, Encr_Char );
1261 Octets_To_Char_Array( Key.n, N_Char );
1262 Octets_To_Char_Array( Key.e, E_Char );
1263 Octets_To_Char_Array( Key.d, D_Char );
1264 Octets_To_Char_Array( Key.p, P_Char );
1265 Octets_To_Char_Array( Key.q, Q_Char );
1266 Octets_To_Char_Array( Key.u, U_Char );
1267 -- call RSA decrypt via C_Wrappers
1268 Plain_Len := Private_RSA_C( Plain_Char, Plain'Length,
1269 Encr_Char , Encr'Length,
1270 N_Char , Key.n'Length,
1271 E_Char , Key.e'Length,
1272 D_Char , Key.d'Length,
1273 P_Char , Key.p'Length,
1274 Q_Char , Key.q'Length,
1275 U_Char , Key.u'Length);
1276 -- convert result back to Octets
1277 Char_Array_To_Octets( Plain_Char, Plain );
1278 -- if length < OAEP_Block'Length,it's 0-led and got trimmed, so move it
1279 if Plain_Len < Plain'Length then
1280 Plain(Plain'Last-Plain_Len+1..Plain'Last):= Plain(Plain'First ..
1281 Plain'First + Plain_Len -1);
1282 Plain(Plain'First .. Plain'Last-Plain_Len) := (others => 0);
1283 end if;
1284 -- no need to return anything!
1285 end Private_RSA;
1286
1287 procedure Octets_To_Char_Array( O : in Raw_Types.Octets;
1288 A : out Interfaces.C.char_array) is
1289 begin
1290 -- check that lengths ARE THE SAME!
1291 if A'Length /= O'Length then
1292 raise Mismatched_Lengths_Error;
1293 end if;
1294 -- copy values over octet by octet
1295 for I in 0 .. O'Length-1 loop
1296 A( A'First + Interfaces.C.size_t( I )) :=
1297 Interfaces.C.Char( Character'Val(O(O'First + I)));
1298 end loop;
1299 end Octets_To_Char_Array;
1300
1301 procedure Char_Array_To_Octets( A : in Interfaces.C.char_array;
1302 O : out Raw_Types.Octets) is
1303 begin
1304 -- check that lengths ARE THE SAME!
1305 if A'Length /= O'Length then
1306 raise Mismatched_Lengths_Error;
1307 end if;
1308 -- copy values over octet by octet
1309 for I in 0..O'Length -1 loop
1310 O( O'First + I ) := Character'Pos( Character(
1311 A( A'First + Interfaces.C.size_t( I )) ));
1312 end loop;
1313 end Char_Array_To_Octets;
1314
1315 end RSA_OAEP;