-- Implementation of TMSR's OAEP with Keccak as hash function -- -- S.MG, 2018 with SMG_Keccak; use SMG_Keccak; -- Keccak is used as hash function with Interfaces; use Interfaces; -- for Unsigned_8 type and bit-level ops with Interfaces.C; use Interfaces.C; -- for interop with C package SMG_OAEP is pragma Pure( SMG_OAEP ); -- stateless, no side effects -> can cache calls -- fixed length of OAEP block in bits and in octets OAEP_LENGTH_BITS : constant := 4096; OAEP_LENGTH_OCTETS : constant := 512; OAEP_HALF_OCTETS : constant := OAEP_LENGTH_OCTETS / 2; TMSR : constant String := "TMSR-RSA"; MAX_LEN_MSG : constant Natural := OAEP_HALF_OCTETS - TMSR'Length - 3; pragma Export( C, MAX_LEN_MSG, "max_len_msg"); -- to be accessed from rsa.c -- subtypes used by the OAEP encrypt/decrypt subtype OAEP_Block is String( 1 .. OAEP_LENGTH_OCTETS ); subtype OAEP_HALF is String( 1 .. OAEP_HALF_OCTETS ); -- copy from Ada String to C char array and back, octet by octet -- This copies first Len characters from A to the first Len positions in S -- NB: this does NOT allocate /check memory! -- Caller has to ensure that: -- S has space for at least Len characters -- A has at least Len characters procedure Char_Array_To_String( A : in Interfaces.C.char_array; Len : in Natural; S : out String); -- This copies first Len characters from S to the first Len positions in A -- NB: there are NO checks or memory allocations here! -- Caller has to make sure that: -- S'Length >= Len -- A has allocated space for at least Len characters procedure String_To_Char_Array( S : in String; Len : in Natural; A : out Interfaces.C.char_array); -- padding & formatting of maximum 1960 bits of the given String -- uses TMSR's OAEP schema: -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message -- where sz1 and sz2 store the length of the message in bits -- the random octets before message are padding to make OAEP_LENGTH_OCTETS -- 2. R = OAEP_HALF_OCTETS random bits -- 3. X = M00 xor hash(R) -- 4. Y = R xor hash(X) -- 5. Result is X || Y -- NB: the Entropy parameter should be random octets from which this method -- will use as many as required for the OAEP encryption of given Msg -- NB: at MOST MAX_LEN_MSG octets of Msg! (Msg at most 1960 bits) procedure OAEP_Encrypt( Msg : in String; Entropy : in OAEP_Block; Output : out OAEP_Block); -- wrapper of oaep_encrypt for direct use from C -- NB: caller HAS TO provide the length of the Message (parameter LenMsg) -- NB: caller HAS TO provide the length of the Entropy (parameter LenEnt) -- NB: caller HAS TO provide the allocated space for result (LenEncr) -- NB: LenEncr HAS TO be at least OAEP_LENGTH_OCTETS! -- NB: LenEnt HAS TO be at least OAEP_LENGTH_OCTETS or this will FAIL! procedure OAEP_Encrypt_C( Msg : in Interfaces.C.char_array; MsgLen : in Interfaces.C.size_t; Entropy : in Interfaces.C.char_array; EntLen : in Interfaces.C.size_t; Encr : out Interfaces.C.char_array; EncrLen : in Interfaces.C.size_t; Success : out Interfaces.C.Int); pragma Export( C, OAEP_Encrypt_C, "oaep_encrypt_c" ); -- This is the opposite of OAEP_Encrypt above. -- @param Encr - an OAEP block previously obtained from OAEP_Encrypt -- @param Len - this will hold the length of the obtained message (in bits!) -- @param Output - the first Len octets of this are the recovered message -- @param Success - set to TRUE if message was recovered, false otherwise -- NB: when Success is FALSE, both Len and Output have undefined values procedure OAEP_Decrypt( Encr : in OAEP_Block; Len : out Natural; Output : out OAEP_HALF; Success : out Boolean); -- wrapper for use from C procedure oaep_decrypt_c( Encr : in Interfaces.C.Char_Array; EncrLen : in Interfaces.C.Int; Decr : out Interfaces.C.Char_Array; DecrLen : in out Interfaces.C.Int; Success : out Interfaces.C.Int); pragma Export( C, oaep_decrypt_c, "oaep_decrypt_c"); -- helper method, xor on strings -- NB: only Output'Length bits will be considered from S1 and S2 -- NB: caller is responsible for S1 and S2 being long enough! procedure XOR_Strings( S1: in String; S2: in String; Output: out String ); -- gnat-specific methods for bit-level operations function Shift_Right( Value : Unsigned_8; Amount : Natural ) return Unsigned_8; pragma Import(Intrinsic, Shift_Right); function Shift_Left( Value : Unsigned_8; Amount : Natural ) return Unsigned_8; pragma Import(Intrinsic, Shift_Left); -- conversions between bitstream and string -- NB: caller has to ensure correct size of output parameter! no checks here. procedure ToString( B: in Bitstream; S: out String ); procedure ToBitstream( S: in String; B: out Bitstream ); -- public wrapper for Sponge to use String for input/output procedure HashKeccak( Input : in String; Output : out String; Block_Len : in Keccak_Rate := Default_Bitrate); -- wrapper for calling Keccak hashing from C, with DEFAULT bitrate -- @param Input the input string, as array of characters (C style) -- @param LenIn the length of the input string (as number of OCTETS) -- @param LenOut the desired number of OCTETS to be returned as output -- @param Output array of at least LenOut characters; will contain the hash -- NB: caller HAS TO provide the length of the Input (parameter LenIn) -- NB: caller HAS TO provide the length of the Output (parameter LenOut) procedure Hash( Input : in Interfaces.C.Char_Array; LenIn : in Interfaces.C.size_t; LenOut : in Interfaces.C.size_t; Output : out Interfaces.C.Char_Array); pragma Export( C, Hash, "hash" ); end SMG_OAEP;