1-- This program is free software; you can redistribute it and/or 2-- modify it under the terms of the GNU General Public License as 3-- published by the Free Software Foundation; either version 2 of the 4-- License, or (at your option) any later version. 5 6-- This program is distributed in the hope that it will be useful, 7-- but WITHOUT ANY WARRANTY; without even the implied warranty of 8-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9-- General Public License for more details. 10 11-- You should have received a copy of the GNU General Public License 12-- along with this program; if not, write to the Free Software 13-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 14-- 02111-1307, USA. 15 16-- As a special exception, if other files instantiate generics from 17-- this unit, or you link this unit with other files to produce an 18-- executable, this unit does not by itself cause the resulting 19-- executable to be covered by the GNU General Public License. This 20-- exception does not however invalidate any other reasons why the 21-- executable file might be covered by the GNU Public License. 22 23 24package body Crypto.Symmetric.KDF_PBKDF2 is 25 26 27 --Interface function for static 64 Bytes Output 28 procedure Derive(This : in out PBKDF2_KDF; 29 Salt : in Bytes; 30 Password : in Bytes; 31 Key : out Bytes) is 32 begin 33 PBKDF2(This => This, 34 Salt => Salt, 35 Password => Password, 36 Key => Key, 37 DK_Len => This.Key_Length); 38 end Derive; 39 40 41 procedure Initialize(This : out PBKDF2_KDF; 42 Key_Length: in Natural) is 43 begin 44 This.Key_Length:=Key_Length; 45 end Initialize; 46 47 48 --function for setting Key Length and security parameter, 49 --used here for setting round count in F_Function 50 procedure Initialize(This : out PBKDF2_KDF; 51 Key_Length : in Natural; 52 Round_Count : in Natural) is 53 begin 54 This.Key_Length:=Key_Length; 55 This.Round_Count:=Round_Count; 56 end Initialize; 57 58 59 60 --actual derivation function, pure PBKDF2 61 procedure PBKDF2(This : in out PBKDF2_KDF'Class; 62 Salt : in Bytes; 63 Password : in Bytes; 64 Key : out Bytes; 65 DK_Len : in Natural) is 66 67 hlen : constant Integer := Hmac_Package.H.Hash_Type'Size/8; 68 DK_Block_Count : Natural; 69 Rest : Natural; 70 Result_Bytes : Bytes(0..DK_Len-1) := (others => 0 ); 71 Temp_Bytes : Bytes(0..hlen-1); 72 73 begin 74 75 Error_Output.Put_Line("Password: " & To_String(Password)); 76 Error_Output.Put_Line("Salt: " & To_String(Salt)); 77 Error_Output.Put_Line("Parameter: " & Integer'Image(This.Round_Count)); 78 79 Error_Output.Put_Line("HLEN: " & Integer'Image(hlen)); 80 81 Error_Output.Put_Line("Key :" & Integer'Image(Key'Length) 82 & "Result_Bytes :" 83 & Integer'Image(Result_Bytes'Length)); 84 85 --calculating amount of blocks required to fill key given the hash length 86 DK_Block_Count := Integer(Float'Ceiling(Float(DK_Len) / Float(hlen))); 87 Rest := DK_Len - (DK_Block_Count-1) * hlen; 88 89 Error_Output.Put_Line("DKBK :" & Integer'Image(DK_Block_Count) 90 & "Rest :" & Integer'Image(Rest)); 91 92 --looping through blocks of the key, applying F_Function 93 for I in 0..DK_Block_Count-1 loop 94 95 if(I = DK_Block_Count-1) 96 then 97 Temp_Bytes := To_Bytes(F_Function(Salt => Salt, 98 Password => Password, 99 Count => This.Round_Count, 100 Round => I+1)); 101 Result_Bytes(I*hlen..I*hlen+Rest-1) := Temp_Bytes(0..Rest-1); 102 else 103 Result_Bytes(I*hlen..I*hlen+hlen-1) 104 := To_Bytes(F_Function(Salt => Salt, 105 Password => Password, 106 Count => This.Round_Count, 107 Round => I+1)); 108 end if; 109 110 end loop; 111 Error_Output.Put_Line("Key :" & Integer'Image(Key'Length) & " " 112 & "Result_Bytes :" 113 & Integer'Image(Result_Bytes'Length)); 114 Key := Result_Bytes; 115 end PBKDF2; 116 117 --Internal function for applying PRF multiple times 118 function F_Function(Salt : in Bytes; 119 Password : in Bytes; 120 Count : in Natural; 121 Round : in Natural) return Hmac_Package.H.Hash_Type is 122 Result_Block : Hmac_Package.H.Hash_Type ; 123 Temp_Block : Hmac_Package.H.Hash_Type; 124 mlen : constant Integer := Hmac_Package.H.Message_Type'Size/8; 125 Temp_Bytes : Bytes(0..mlen-1) := (others =>0); 126 hlen : constant Integer := Hmac_Package.H.Hash_Type'Size/8; 127 Salt_Bytes : Bytes(0..Salt'Length+4-1); 128 129 use Hmac_Package; 130 Context : HMAC_Context; 131 132 Position : Natural := 0; 133 134 begin 135 136 Temp_Bytes(0..Password'Length-1):=Password; 137 Context.Init(Key => To_Message_Type(Temp_Bytes)); 138 139 Salt_Bytes := (others => 0); 140 Salt_Bytes(0..Salt'Length-1) := Salt; 141 Salt_Bytes(Salt'Length..Salt'Length+3):= To_Bytes(Word(Round))(0..3); 142 143 while Position + 64 < Salt_Bytes'Length loop 144 Temp_Bytes(0..63) := Salt_Bytes(Position..Position+63); 145 Context.Sign(Message_Block => To_Message_Type(Temp_Bytes)); 146 Position := Position+64; 147 end loop; 148 149 Temp_Bytes := (others => 0); 150 Temp_Bytes(0..Salt_Bytes'Length - Position -1) 151 := Salt_Bytes(Position..Salt_Bytes'Length-1); 152 Context.Final_Sign 153 (Final_Message_Block => To_Message_Type(Temp_Bytes), 154 Final_Message_Block_Length => Hmac_Package.H.Message_Block_Length_Type 155 (Salt_Bytes'Length - Position), 156 Tag => Temp_Block); 157 158 Result_Block:= Temp_Block; 159 160 for I in 2..Count loop 161 Temp_Bytes := (others => 0); 162 Temp_Bytes(0..hlen-1) 163 := Crypto.Symmetric.KDF_PBKDF2.To_Bytes(Temp_Block); 164 Context.Final_Sign 165 (Final_Message_Block => To_Message_Type(Temp_Bytes), 166 Final_Message_Block_Length => 167 Hmac_Package.H.Message_Block_Length_Type(hlen), 168 Tag => Temp_Block); 169 170 Result_Block := Result_Block xor Temp_Block; 171 172 end loop; 173 174 return Result_Block; 175 end; 176 177 --function for utility, accepting strings and key length (in Bytes) 178 procedure Derive(This : in out PBKDF2_KDF; 179 Salt : in String; 180 Password : in String; 181 Key : out Bytes; 182 DK_Len : in Natural) is 183 begin 184 PBKDF2(This => This, 185 Salt => To_Bytes(Salt), 186 Password => To_Bytes(Password), 187 Key => Key, 188 DK_Len => DK_Len); 189 190 end Derive; 191 pragma Unreferenced (Derive); 192 193 194 195 196end Crypto.Symmetric.KDF_PBKDF2; 197