-- 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; -- 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 ); -- 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 OAEP_LENGTH_OCTETS - 11 octets of Msg! (Msg at most 1960 bits) procedure OAEP_Encrypt( Msg : in String; Entropy : in OAEP_Block; Output : out OAEP_Block); -- 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); -- 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 from C -- @param Input the input string, as array of characters (C style) -- @param LenIn the length of the input string (as number of BITS) -- @param LenOut the desired number of bits to be returned as output -- @param Block_Len the bitrate used by the Keccak sponge (number of BITS) -- @return an array of characters with first LenOut bits set to Keccak output -- NB: caller HAS TO provide the length of the Input (parameter LenIn) -- NB: caller HAS TO provide the length of the Output (parameter LenOut) function Hash( Input : Interfaces.C.Char_Array; LenIn : Interfaces.C.size_t; LenOut : Interfaces.C.size_t; Block_Len : Interfaces.C.int := Default_Bitrate) return Interfaces.C.Char_Array; pragma Export( C, Hash, "hash" ); end SMG_OAEP;