-- Ada implementation of RSA with OAEP according to TMSR and Eulora spec -- Uses: -- - Eulora's raw types (Ada, raw_types.ads) -- - Keccak hashes (Ada, keccak.ads/adb) -- - OAEP schema (Ada, oaep.ads/adb) -- - RNG (Ada, rng.ads/adb) for true random padding -- - C wrappers lib (C, c_wrappers/) for: -- - MPI (C, mpi/) -- - RSA (C, rsa/rsa.c) -- -- S.MG, 2018 with Raw_Types; with Interfaces.C; use Interfaces.C; package RSA_OAEP is -- exception for mismatched lengths when converting octets <-> char arrays Mismatched_Lengths_Error: exception; -- public RSA key with n,e stored as raw octets type RSA_pkey is record n : Raw_Types.RSA_len; --public modulus e : Raw_Types.RSA_half; --public exponent end record; --RSA_pkey -- private (secret) RSA key with components stored as raw octets type RSA_skey is record n : Raw_Types.RSA_len; --public modulus e : Raw_Types.RSA_half; --public exponent d : Raw_Types.RSA_len; --secret exponent e*d=1 mod phi; phi=(p-1)*(q-1) p : Raw_Types.RSA_half; --prime p q : Raw_Types.RSA_half; --prime q u : Raw_Types.RSA_half; --inverse of p mod q; for faster calculations end record; --RSA_skey -- Encryption RSA+OAEP (i.e. using public key) -- NB: at most OAEP.MAX_LEN_MSG octets from Plain will be encrypted! -- Relies directly on: -- oaep.adb/ads -- c_wrappers.c ( RSA ) -- rng.adb/ads ( random padding ) procedure Encrypt( Plain: in Raw_Types.Octets; Key : in RSA_pkey; Encr : out Raw_Types.RSA_len ); -- Decryption RSA+OAEP (i.e. using private/secret key) -- The opposite of Encrypt above. -- NB: Plain has to have ENOUGH space for result! -- Result can be at most OAEP.MAX_LEN_MSG octets. -- Relies directly on: -- oaep.adb/ads -- c_wrappers.c (RSA) -- Plain_Len gives the length in OCTETS of the decrypted message. procedure Decrypt( Encr : in Raw_Types.RSA_len; Key : in RSA_skey; Plain : out Raw_Types.Octets; Plain_Len : out Natural; Success : out Boolean); --helper methods: -- mainly conversions to/from C's char* and imports from C_wrappers -- encrypt with public RSA key given as struct, Ada style -- NB: result is potentially 0-led (i.e. at end of Encr not at start!) procedure Public_RSA( Plain: in Raw_Types.Octets; Key : in RSA_pkey; Encr : out Raw_Types.RSA_len); -- encrypt with public RSA key given as char arrays, via C_Wrappers -- this returns the length of result because C functions trim leading 0s! function Public_RSA_C( Encr : out Interfaces.C.char_array; Encr_Len : in Integer; Plain : in Interfaces.C.char_array; Plain_Len : in Integer; RSA_N : in Interfaces.C.char_array; N_Len : in Integer; RSA_E : in Interfaces.C.char_array; E_Len : in Integer) return Integer; pragma Import(C, Public_RSA_C, "public_rsa_octets"); -- decrypt with private RSA key given as struct, Ada style -- NB: Plain has to have ENOUGH space! -- NB: Result is potentially 0-led (i.e. at the end of Plain, not at start!) -- @return actual length of result procedure Private_RSA( Encr : in Raw_Types.RSA_len; Key : in RSA_skey; Plain : out Raw_Types.Octets); -- encrypt with private/secret RSA key given as char arrays (via C_wrappers) -- this returns length because C methods trim leading 0s function Private_RSA_C( Plain : out Interfaces.C.char_array; Plain_Len : in Integer; Encr : in Interfaces.C.char_array; Encr_Len : in Integer; RSA_N : in Interfaces.C.char_array; N_Len : in Integer; RSA_E : in Interfaces.C.char_array; E_Len : in Integer; RSA_D : in Interfaces.C.char_array; D_Len : in Integer; RSA_P : in Interfaces.C.char_array; P_Len : in Integer; RSA_Q : in Interfaces.C.char_array; Q_Len : in Integer; RSA_U : in Interfaces.C.char_array; U_Len : in Integer) return Integer; pragma Import( C, Private_RSA_C, "private_rsa_octets" ); -- convert from Ada's Octets (array of octets) to C's char* (char_array) -- This copies the octets from O to the beginning of A -- NB: there are NO checks or memory allocations here! -- Caller has to make sure that: -- A has allocated space for at least O'Length octets! procedure Octets_To_Char_Array( O : in Raw_Types.Octets; A : out Interfaces.C.char_array); -- This copies first O'Length characters from A to O -- NB: this does NOT allocate /check memory! -- Caller has to ensure that: -- A has space at least O'Length characters procedure Char_Array_To_Octets( A : in Interfaces.C.char_array; O : out Raw_Types.Octets); end RSA_OAEP;