-
+ 982B3D71F5AE114ABC3A8A5C754E0F645D62694BEDEF479DEC7D51DDC454AC23F19EDF27526B2F1A5D91A73EE0111C2761C29551E5C6894D4844660E2981717C
smg_comms/src/oaep.adb
(0 . 0)(1 . 176)
789 -- S.MG, 2018
790
791 package body OAEP is
792
793 -- padding & formatting of maximum MAX_LEN_MSG*8 bits of the given input
794 -- uses TMSR's OAEP schema:
795 -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message
796 -- where sz1 and sz2 store the length of the message in bits
797 -- the random octets before message are padding to make OAEP_LENGTH_OCTETS
798 -- 2. R = OAEP_HALF_OCTETS random bits
799 -- 3. X = M00 xor hash(R)
800 -- 4. Y = R xor hash(X)
801 -- 5. Result is X || Y
802 -- NB: the Entropy parameter should be random octets from which this method
803 -- will use as many as required for the OAEP encryption of given Msg
804 -- NB: at MOST MAX_LEN_MSG octets of Msg! (Msg at most 1960 bits)
805 procedure OAEP_Encrypt( Msg : in Raw_Types.Octets;
806 Entropy : in OAEP_Block;
807 Output : out OAEP_Block) is
808 M00 : OAEP_HALF;
809 R : OAEP_HALF;
810 HashR : OAEP_HALF;
811 X : OAEP_HALF;
812 HashX : OAEP_HALF;
813 Y : OAEP_HALF;
814 MsgLen : Natural;
815 PadLen : Natural;
816 begin
817 -- calculate maximum length of msg and needed amount of padding
818 -- make sure also that only MAX_LEN_MSG octets at most are used from Msg
819 MsgLen := Msg'Length; -- real msg length
820 if MsgLen > MAX_LEN_MSG then
821 MsgLen := MAX_LEN_MSG; --only first MAX_LEN_MSG octets used
822 PadLen := 0; --no padding needed
823 else
824 PadLen := MAX_LEN_MSG - MsgLen; -- add padding as needed
825 end if;
826
827 -- step 1: header and format to obtain M00
828 -- first octet is random bits
829 M00( M00'First ) := Entropy( Entropy'First );
830
831 -- next 2 octets hold the used length of Msg (number of octets)
832 M00( M00'First + 2) := Unsigned_8( ( MsgLen * 8 ) mod 256 );
833 M00( M00'First + 1) := Unsigned_8( ( (MsgLen * 8 ) / 256 ) mod 256 );
834
835 -- next 8 octets are reserved for later use, currently "TMSR-RSA"
836 M00( M00'First + 3 .. M00'First + 10 ) := TMSR;
837
838 -- random bits for padding, if Msg is less than maximum length
839 for I in 1 .. PadLen loop
840 M00( M00'First + 10 + I ) := Entropy( Entropy'First + I );
841 end loop;
842
843 -- the message itself
844 M00( M00'Last - MsgLen + 1 .. M00'Last ) :=
845 Msg( Msg'First .. Msg'First + MsgLen - 1 );
846
847 -- step 2: R = Raw_Types.OAEP_HALF_OCTETS random octets
848 -- can take LAST octets from given entropy as they are NOT used before
849 -- (even if original message was empty, padding uses at most half - 10
850 -- while entropy has full block length)
851 R := Entropy( Entropy'Last - OAEP_HALF_OCTETS + 1 .. Entropy'Last );
852
853 -- step 3: X = M00 xor hash(R)
854 HashKeccak( R, HashR );
855 X := XOR_Octets(M00, HashR);
856
857 -- step 4: Y = R xor hash(X)
858 HashKeccak( X, HashX );
859 Y := XOR_Octets(R, HashX);
860
861 -- step 5: Output is X || Y
862 Output( Output'First .. Output'First + X'Length - 1 ) := X;
863 Output( Output'Last - Y'Length + 1 .. Output'Last ) := Y;
864
865 end OAEP_Encrypt;
866
867 procedure OAEP_Decrypt( Encr : in OAEP_Block;
868 Len : out Natural;
869 Output : out OAEP_HALF;
870 Success : out Boolean ) is
871 X, Y, M, R : OAEP_HALF;
872 HashX, HashR : OAEP_HALF;
873 LenOctets : Natural;
874 begin
875 -- step 1: separate X and Y
876 X := Encr( Encr'First .. Encr'First + X'Length - 1 );
877 Y := Encr( Encr'Last - Y'Length + 1 .. Encr'Last );
878
879 -- step 2: R = Y xor hash(X)
880 HashKeccak( X, HashX );
881 R := XOR_Octets(Y, HashX);
882
883 -- step 3: M = X xor hash(R)
884 HashKeccak( R, HashR );
885 M := XOR_Octets(X, HashR);
886
887 -- step 4: extract length and message
888 Len := Natural(M( M'First + 1 )) * 256 +
889 Natural(M( M'First + 2 ));
890 LenOctets := Len / 8;
891
892 if LenOctets > MAX_LEN_MSG or LenOctets < 0 then
893 Success := False; -- error, failed to retrieve message
894 else
895 Success := True;
896 Output( Output'First .. Output'First + LenOctets - 1 ) :=
897 M( M'Last - LenOctets + 1 .. M'Last );
898 end if;
899
900 end OAEP_Decrypt;
901
902 -- private, helper methods
903 procedure HashKeccak(Input : in Raw_Types.Octets;
904 Output : out Raw_Types.Octets;
905 Block_Len : in Keccak.Keccak_Rate :=
906 Keccak.Default_Bitrate) is
907 BIn : Keccak.Bitstream( 0 .. Input'Length * 8 - 1 );
908 BOut : Keccak.Bitstream( 0 .. Output'Length * 8 - 1 );
909 begin
910 ToBitstream( Input, BIn );
911 Keccak.Sponge( BIn, BOut, Block_Len );
912 ToOctets( BOut, Output );
913 end HashKeccak;
914
915 function XOR_Octets(A : in OAEP_HALF;
916 B : in OAEP_HALF)
917 return OAEP_HALF is
918 R : OAEP_HALF;
919 begin
920 for I in R'Range loop
921 R(I) := A(I) xor B(I);
922 end loop;
923 return R;
924 end XOR_Octets;
925
926 -- conversion between types
927 procedure ToOctets(B: in Keccak.Bitstream; O: out Raw_Types.Octets ) is
928 Pos : Natural;
929 begin
930 Pos := B'First;
931 for I in O'Range loop
932 O(I) := Unsigned_8( B( Pos ) ) +
933 Unsigned_8( B( Pos + 1 ) ) * 2 +
934 Unsigned_8( B( Pos + 2 ) ) * 4 +
935 Unsigned_8( B( Pos + 3 ) ) * 8 +
936 Unsigned_8( B( Pos + 4 ) ) * 16 +
937 Unsigned_8( B( Pos + 5 ) ) * 32 +
938 Unsigned_8( B( Pos + 6 ) ) * 64 +
939 Unsigned_8( B( Pos + 7 ) ) * 128;
940 Pos := Pos + 8;
941 end loop;
942 end ToOctets;
943
944 procedure ToBitstream(O: in Raw_Types.Octets; B: out Keccak.Bitstream ) is
945 V : Unsigned_8;
946 Pos : Natural;
947 begin
948 Pos := B'First;
949 for I in O'Range loop
950 V := O( I );
951 B( Pos ) := Keccak.Bit( V and 1 );
952 B( Pos + 1 ) := Keccak.Bit( Shift_Right( V, 1 ) and 1 );
953 B( Pos + 2 ) := Keccak.Bit( Shift_Right( V, 2 ) and 1 );
954 B( Pos + 3 ) := Keccak.Bit( Shift_Right( V, 3 ) and 1 );
955 B( Pos + 4 ) := Keccak.Bit( Shift_Right( V, 4 ) and 1 );
956 B( Pos + 5 ) := Keccak.Bit( Shift_Right( V, 5 ) and 1 );
957 B( Pos + 6 ) := Keccak.Bit( Shift_Right( V, 6 ) and 1 );
958 B( Pos + 7 ) := Keccak.Bit( Shift_Right( V, 7 ) and 1 );
959
960 Pos := Pos + 8;
961 end loop;
962 end ToBitstream;
963
964 end OAEP;