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