Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / hostapd / src / crypto / ms_funcs.c
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "sha1.h"
19 #include "ms_funcs.h"
20 #include "crypto.h"
21 #include "rc4.h"
22
23
24 /**
25  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
26  * @peer_challenge: 16-octet PeerChallenge (IN)
27  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
28  * @username: 0-to-256-char UserName (IN)
29  * @username_len: Length of username
30  * @challenge: 8-octet Challenge (OUT)
31  */
32 static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
33                            const u8 *username, size_t username_len,
34                            u8 *challenge)
35 {
36         u8 hash[SHA1_MAC_LEN];
37         const unsigned char *addr[3];
38         size_t len[3];
39
40         addr[0] = peer_challenge;
41         len[0] = 16;
42         addr[1] = auth_challenge;
43         len[1] = 16;
44         addr[2] = username;
45         len[2] = username_len;
46
47         sha1_vector(3, addr, len, hash);
48         os_memcpy(challenge, hash, 8);
49 }
50
51
52 /**
53  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
54  * @password: 0-to-256-unicode-char Password (IN; ASCII)
55  * @password_len: Length of password
56  * @password_hash: 16-octet PasswordHash (OUT)
57  */
58 void nt_password_hash(const u8 *password, size_t password_len,
59                       u8 *password_hash)
60 {
61         u8 buf[512], *pos;
62         size_t i, len;
63
64         if (password_len > 256)
65                 password_len = 256;
66
67         /* Convert password into unicode */
68         for (i = 0; i < password_len; i++) {
69                 buf[2 * i] = password[i];
70                 buf[2 * i + 1] = 0;
71         }
72
73         len = password_len * 2;
74         pos = buf;
75         md4_vector(1, (const u8 **) &pos, &len, password_hash);
76 }
77
78
79 /**
80  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
81  * @password_hash: 16-octet PasswordHash (IN)
82  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
83  */
84 void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
85 {
86         size_t len = 16;
87         md4_vector(1, &password_hash, &len, password_hash_hash);
88 }
89
90
91 /**
92  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
93  * @challenge: 8-octet Challenge (IN)
94  * @password_hash: 16-octet PasswordHash (IN)
95  * @response: 24-octet Response (OUT)
96  */
97 void challenge_response(const u8 *challenge, const u8 *password_hash,
98                         u8 *response)
99 {
100         u8 zpwd[7];
101         des_encrypt(challenge, password_hash, response);
102         des_encrypt(challenge, password_hash + 7, response + 8);
103         zpwd[0] = password_hash[14];
104         zpwd[1] = password_hash[15];
105         os_memset(zpwd + 2, 0, 5);
106         des_encrypt(challenge, zpwd, response + 16);
107 }
108
109
110 /**
111  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
112  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
113  * @peer_challenge: 16-octet PeerChallenge (IN)
114  * @username: 0-to-256-char UserName (IN)
115  * @username_len: Length of username
116  * @password: 0-to-256-unicode-char Password (IN; ASCII)
117  * @password_len: Length of password
118  * @response: 24-octet Response (OUT)
119  */
120 void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
121                           const u8 *username, size_t username_len,
122                           const u8 *password, size_t password_len,
123                           u8 *response)
124 {
125         u8 challenge[8];
126         u8 password_hash[16];
127
128         challenge_hash(peer_challenge, auth_challenge, username, username_len,
129                        challenge);
130         nt_password_hash(password, password_len, password_hash);
131         challenge_response(challenge, password_hash, response);
132 }
133
134
135 /**
136  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
137  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
138  * @peer_challenge: 16-octet PeerChallenge (IN)
139  * @username: 0-to-256-char UserName (IN)
140  * @username_len: Length of username
141  * @password_hash: 16-octet PasswordHash (IN)
142  * @response: 24-octet Response (OUT)
143  */
144 void generate_nt_response_pwhash(const u8 *auth_challenge,
145                                  const u8 *peer_challenge,
146                                  const u8 *username, size_t username_len,
147                                  const u8 *password_hash,
148                                  u8 *response)
149 {
150         u8 challenge[8];
151
152         challenge_hash(peer_challenge, auth_challenge, username, username_len,
153                        challenge);
154         challenge_response(challenge, password_hash, response);
155 }
156
157
158 /**
159  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
160  * @password_hash: 16-octet PasswordHash (IN)
161  * @nt_response: 24-octet NT-Response (IN)
162  * @peer_challenge: 16-octet PeerChallenge (IN)
163  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
164  * @username: 0-to-256-char UserName (IN)
165  * @username_len: Length of username
166  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
167  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
168  */
169 void generate_authenticator_response_pwhash(
170         const u8 *password_hash,
171         const u8 *peer_challenge, const u8 *auth_challenge,
172         const u8 *username, size_t username_len,
173         const u8 *nt_response, u8 *response)
174 {
175         static const u8 magic1[39] = {
176                 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
177                 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
178                 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
179                 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
180         };
181         static const u8 magic2[41] = {
182                 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
183                 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
184                 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
185                 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
186                 0x6E
187         };
188
189         u8 password_hash_hash[16], challenge[8];
190         const unsigned char *addr1[3];
191         const size_t len1[3] = { 16, 24, sizeof(magic1) };
192         const unsigned char *addr2[3];
193         const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
194
195         addr1[0] = password_hash_hash;
196         addr1[1] = nt_response;
197         addr1[2] = magic1;
198
199         addr2[0] = response;
200         addr2[1] = challenge;
201         addr2[2] = magic2;
202
203         hash_nt_password_hash(password_hash, password_hash_hash);
204         sha1_vector(3, addr1, len1, response);
205
206         challenge_hash(peer_challenge, auth_challenge, username, username_len,
207                        challenge);
208         sha1_vector(3, addr2, len2, response);
209 }
210
211
212 /**
213  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
214  * @password: 0-to-256-unicode-char Password (IN; ASCII)
215  * @password_len: Length of password
216  * @nt_response: 24-octet NT-Response (IN)
217  * @peer_challenge: 16-octet PeerChallenge (IN)
218  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
219  * @username: 0-to-256-char UserName (IN)
220  * @username_len: Length of username
221  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
222  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
223  */
224 void generate_authenticator_response(const u8 *password, size_t password_len,
225                                      const u8 *peer_challenge,
226                                      const u8 *auth_challenge,
227                                      const u8 *username, size_t username_len,
228                                      const u8 *nt_response, u8 *response)
229 {
230         u8 password_hash[16];
231         nt_password_hash(password, password_len, password_hash);
232         generate_authenticator_response_pwhash(password_hash,
233                                                peer_challenge, auth_challenge,
234                                                username, username_len,
235                                                nt_response, response);
236 }
237
238
239 /**
240  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
241  * @challenge: 8-octet Challenge (IN)
242  * @password: 0-to-256-unicode-char Password (IN; ASCII)
243  * @password_len: Length of password
244  * @response: 24-octet Response (OUT)
245  */
246 void nt_challenge_response(const u8 *challenge, const u8 *password,
247                            size_t password_len, u8 *response)
248 {
249         u8 password_hash[16];
250         nt_password_hash(password, password_len, password_hash);
251         challenge_response(challenge, password_hash, response);
252 }
253
254
255 /**
256  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
257  * @password_hash_hash: 16-octet PasswordHashHash (IN)
258  * @nt_response: 24-octet NTResponse (IN)
259  * @master_key: 16-octet MasterKey (OUT)
260  */
261 void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
262                     u8 *master_key)
263 {
264         static const u8 magic1[27] = {
265                 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
266                 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
267                 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
268         };
269         const unsigned char *addr[3];
270         const size_t len[3] = { 16, 24, sizeof(magic1) };
271         u8 hash[SHA1_MAC_LEN];
272
273         addr[0] = password_hash_hash;
274         addr[1] = nt_response;
275         addr[2] = magic1;
276
277         sha1_vector(3, addr, len, hash);
278         os_memcpy(master_key, hash, 16);
279 }
280
281
282 /**
283  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
284  * @master_key: 16-octet MasterKey (IN)
285  * @session_key: 8-to-16 octet SessionKey (OUT)
286  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
287  * @is_send: IsSend (IN, BOOLEAN)
288  * @is_server: IsServer (IN, BOOLEAN)
289  */
290 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
291                              size_t session_key_len, int is_send,
292                              int is_server)
293 {
294         static const u8 magic2[84] = {
295                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
296                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
297                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
298                 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
299                 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
300                 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
301                 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
302                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
303                 0x6b, 0x65, 0x79, 0x2e
304         };
305         static const u8 magic3[84] = {
306                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
307                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
308                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
309                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
310                 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
311                 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
312                 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
313                 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
314                 0x6b, 0x65, 0x79, 0x2e
315         };
316         static const u8 shs_pad1[40] = {
317                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
321         };
322
323         static const u8 shs_pad2[40] = {
324                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
325                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
326                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
327                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
328         };
329         u8 digest[SHA1_MAC_LEN];
330         const unsigned char *addr[4];
331         const size_t len[4] = { 16, 40, 84, 40 };
332
333         addr[0] = master_key;
334         addr[1] = shs_pad1;
335         if (is_send) {
336                 addr[2] = is_server ? magic3 : magic2;
337         } else {
338                 addr[2] = is_server ? magic2 : magic3;
339         }
340         addr[3] = shs_pad2;
341
342         sha1_vector(4, addr, len, digest);
343
344         if (session_key_len > SHA1_MAC_LEN)
345                 session_key_len = SHA1_MAC_LEN;
346         os_memcpy(session_key, digest, session_key_len);
347 }
348
349
350 #define PWBLOCK_LEN 516
351
352 /**
353  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
354  * @password: 0-to-256-unicode-char Password (IN; ASCII)
355  * @password_len: Length of password
356  * @password_hash: 16-octet PasswordHash (IN)
357  * @pw_block: 516-byte PwBlock (OUT)
358  * Returns: 0 on success, -1 on failure
359  */
360 int encrypt_pw_block_with_password_hash(
361         const u8 *password, size_t password_len,
362         const u8 *password_hash, u8 *pw_block)
363 {
364         size_t i, offset;
365         u8 *pos;
366
367         if (password_len > 256)
368                 return -1;
369
370         os_memset(pw_block, 0, PWBLOCK_LEN);
371         offset = (256 - password_len) * 2;
372         if (os_get_random(pw_block, offset) < 0)
373                 return -1;
374         for (i = 0; i < password_len; i++)
375                 pw_block[offset + i * 2] = password[i];
376         /*
377          * PasswordLength is 4 octets, but since the maximum password length is
378          * 256, only first two (in little endian byte order) can be non-zero.
379          */
380         pos = &pw_block[2 * 256];
381         WPA_PUT_LE16(pos, password_len * 2);
382         rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
383         return 0;
384 }
385
386
387 /**
388  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
389  * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
390  * @new_password_len: Length of new_password
391  * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
392  * @old_password_len: Length of old_password
393  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
394  * Returns: 0 on success, -1 on failure
395  */
396 int new_password_encrypted_with_old_nt_password_hash(
397         const u8 *new_password, size_t new_password_len,
398         const u8 *old_password, size_t old_password_len,
399         u8 *encrypted_pw_block)
400 {
401         u8 password_hash[16];
402
403         nt_password_hash(old_password, old_password_len, password_hash);
404         if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
405                                                 password_hash,
406                                                 encrypted_pw_block))
407                 return -1;
408         return 0;
409 }
410
411
412 /**
413  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
414  * @password_hash: 16-octer PasswordHash (IN)
415  * @block: 16-octet Block (IN)
416  * @cypher: 16-octer Cypher (OUT)
417  */
418 void nt_password_hash_encrypted_with_block(const u8 *password_hash,
419                                            const u8 *block, u8 *cypher)
420 {
421         des_encrypt(password_hash, block, cypher);
422         des_encrypt(password_hash + 8, block + 7, cypher + 8);
423 }
424
425
426 /**
427  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
428  * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
429  * @new_password_len: Length of new_password
430  * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
431  * @old_password_len: Length of old_password
432  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
433  */
434 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
435         const u8 *new_password, size_t new_password_len,
436         const u8 *old_password, size_t old_password_len,
437         u8 *encrypted_password_hash)
438 {
439         u8 old_password_hash[16], new_password_hash[16];
440
441         nt_password_hash(old_password, old_password_len, old_password_hash);
442         nt_password_hash(new_password, new_password_len, new_password_hash);
443         nt_password_hash_encrypted_with_block(old_password_hash,
444                                               new_password_hash,
445                                               encrypted_password_hash);
446 }