-- Packing/unpacking for Eulora's communication protocol: -- Serpent Message to/from Serpent Packet -- RSA Message to/from RSA Packet -- S.MG, 2018 package body Packing is -- Packing a Serpent message into Serpent package, using the given key function Pack( Msg : in Raw_Types.Serpent_Msg; K : in Serpent.Key ) return Raw_Types.Serpent_Pkt is -- single Serpent blocks containing plain / encrypted data Plain : Serpent.Block; Encr : Serpent.Block; -- Serpent Key Schedule - needed for direct encr/decr calls KS : Serpent.Key_Schedule; -- final resulting Serpent package Pkt : Raw_Types.Serpent_Pkt := (others => 0); begin -- prepare the Serpent key schedule based on given key Serpent.Prepare_Key( K, KS ); -- encrypt message block by block and copy result in packet for I in 1 .. S_Blocks loop -- get current block to encrypt Plain := Msg( Msg'First + (I-1) * Block_Len .. Msg'First + I * Block_Len - 1 ); -- encrypt with Serpent Serpent.Encrypt( KS, Plain, Encr ); -- copy result to output packet Pkt( Pkt'First + (I-1) * Block_Len .. Pkt'First + I * Block_Len - 1 ) := Encr; end loop; -- return result return Pkt; end Pack; -- Unpacking a Serpent packet into contained message, using the given key function Unpack( Pkt : in Raw_Types.Serpent_Pkt; K : in Serpent.Key) return Raw_Types.Serpent_Msg is -- single Serpent blocks containing plain / encrypted data Plain : Serpent.Block; Encr : Serpent.Block; -- Serpent Key Schedule - needed for direct encr/decr calls KS : Serpent.Key_Schedule; -- the message extracted from the given packet Msg : Raw_Types.Serpent_Msg := (others => 0); begin -- prepare the Serpent key for use Serpent.Prepare_Key( K, KS ); -- decrypt the Serpent packet block by block for I in 1 .. S_Blocks loop -- get current block from input and decrypt Encr := Pkt( Pkt'First + (I-1) * Block_Len .. Pkt'First + I * Block_Len - 1 ); Serpent.Decrypt( KS, Encr, Plain ); -- copy result to its correct position in final output Msg( Msg'First + (I-1) * Block_Len .. Msg'First + I * Block_Len - 1 ) := Plain; end loop; -- return the result - the message content of given package return Msg; end Unpack; -- Packing a RSA message into RSA packet, using the given key function Pack( Msg : in Raw_Types.RSA_Msg; K : in RSA_OAEP.RSA_pkey) return Raw_Types.RSA_Pkt is -- a chunk that can be processed via rsa+oaep at any given time Chunk: Raw_Types.Octets(1..Raw_Types.OAEP_MAX_LEN) := (others => 0); -- number of chunks in the message to process -- NO incomplete chunks will be processed! -- NB: values are set so that there are no incomplete blocks here N : constant Natural := Msg'Length / Chunk'Length; -- intermediate result, as obtained from rsa_oaep Encr: Raw_Types.RSA_len := (others => 0); -- final resulting RSA Packet Pkt : Raw_Types.RSA_Pkt := (others => 0); begin -- there should ALWAYS be precisely N chunks in Msg to feed to rsa_oaep -- process chunks of Msg one at a time for I in 1..N loop -- get current chunk Chunk := Msg(Msg'First + (I-1) * Chunk'Length .. Msg'First + I * Chunk'Length - 1 ); -- call rsa oaep encrypt on current chunk RSA_OAEP.Encrypt( Chunk, K, Encr ); -- copy result to its place in final packet Pkt( Pkt'First + (I-1) * Encr'Length .. Pkt'First + I * Encr'Length - 1 ) := Encr; end loop; -- return final result return Pkt; end Pack; -- Unpacking a RSA packet into contained message, using the given key function Unpack( Pkt : in Raw_Types.RSA_Pkt; K : in RSA_OAEP.RSA_skey; Success : out Boolean) return Raw_Types.RSA_Msg is -- a chunk - basically input for RSA_OAEP.Decrypt Chunk : Raw_Types.RSA_len := (others => 0); -- intermediate result of rsa_oaep decrypt Decr : Raw_Types.Octets( 1..Raw_Types.OAEP_MAX_LEN ) := (others => 0); Len : Natural; Flag : Boolean; -- number of chunks in the packet -- NB: there should be only FULL chunks! otherwise -> fail N : constant Natural := Pkt'Length / Chunk'Length; -- final resulting message content of the given RSA packet Msg : Raw_Types.RSA_Msg := (others => 0); begin -- initialize Success flag Success := True; -- process given packet, chunk by chunk for I in 1..N loop -- get current chunk Chunk := Pkt( Pkt'First + (I-1) * Chunk'Length .. Pkt'First + I * Chunk'Length - 1 ); -- decrypt it via rsa+oaep RSA_OAEP.Decrypt( Chunk, K, Decr, Len, Flag ); -- check result and if ok then copy it to final result at its place -- NB: if returned length is EVER less than OAEP_MAX_LEN then -> fail! -- the reason for above: there will be undefined bits in the output! if Len /= Raw_Types.OAEP_MAX_LEN or (not Flag) then Success := False; return Msg; else Msg( Msg'First + (I-1) * Decr'Length .. Msg'First + I * Decr'Length - 1 ) := Decr; end if; end loop; -- return obtained message return Msg; end Unpack; end Packing;