]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/ms_funcs.c
This commit was generated by cvs2svn to compensate for changes in r159952,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / ms_funcs.c
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "common.h"
20 #include "sha1.h"
21 #include "ms_funcs.h"
22 #include "crypto.h"
23 #include "rc4.h"
24
25
26 /**
27  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
28  * @peer_challenge: 16-octet PeerChallenge (IN)
29  * @auth_challenge: 16-octet AuthChallenge (IN)
30  * @username: 0-to-256-char UserName (IN)
31  * @username_len: Length of username
32  * @challenge: 8-octet Challenge (OUT)
33  */
34 static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
35                            const u8 *username, size_t username_len,
36                            u8 *challenge)
37 {
38         u8 hash[SHA1_MAC_LEN];
39         const unsigned char *addr[3];
40         size_t len[3];
41
42         addr[0] = peer_challenge;
43         len[0] = 16;
44         addr[1] = auth_challenge;
45         len[1] = 16;
46         addr[2] = username;
47         len[2] = username_len;
48
49         sha1_vector(3, addr, len, hash);
50         memcpy(challenge, hash, 8);
51 }
52
53
54 /**
55  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
56  * @password: 0-to-256-unicode-char Password (IN)
57  * @password_len: Length of password
58  * @password_hash: 16-octet PasswordHash (OUT)
59  */
60 void nt_password_hash(const u8 *password, size_t password_len,
61                       u8 *password_hash)
62 {
63         u8 *buf;
64         int i;
65         size_t len;
66
67         /* Convert password into unicode */
68         buf = malloc(password_len * 2);
69         if (buf == NULL)
70                 return;
71         memset(buf, 0, password_len * 2);
72         for (i = 0; i < password_len; i++)
73                 buf[2 * i] = password[i];
74
75         len = password_len * 2;
76         md4_vector(1, (const u8 **) &buf, &len, password_hash);
77         free(buf);
78 }
79
80
81 /**
82  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
83  * @password_hash: 16-octet PasswordHash (IN)
84  * @password_hash_hash: 16-octet PaswordHashHash (OUT)
85  */
86 void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
87 {
88         size_t len = 16;
89         md4_vector(1, &password_hash, &len, password_hash_hash);
90 }
91
92
93 /**
94  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
95  * @challenge: 8-octet Challenge (IN)
96  * @password_hash: 16-octet PasswordHash (IN)
97  * @response: 24-octet Response (OUT)
98  */
99 void challenge_response(const u8 *challenge, const u8 *password_hash,
100                         u8 *response)
101 {
102         u8 zpwd[7];
103         des_encrypt(challenge, password_hash, response);
104         des_encrypt(challenge, password_hash + 7, response + 8);
105         zpwd[0] = password_hash[14];
106         zpwd[1] = password_hash[15];
107         memset(zpwd + 2, 0, 5);
108         des_encrypt(challenge, zpwd, response + 16);
109 }
110
111
112 /**
113  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
114  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
115  * @peer_hallenge: 16-octet PeerChallenge (IN)
116  * @username: 0-to-256-char UserName (IN)
117  * @username_len: Length of username
118  * @password: 0-to-256-unicode-char Password (IN)
119  * @password_len: Length of password
120  * @response: 24-octet Response (OUT)
121  */
122 void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
123                           const u8 *username, size_t username_len,
124                           const u8 *password, size_t password_len,
125                           u8 *response)
126 {
127         u8 challenge[8];
128         u8 password_hash[16];
129
130         challenge_hash(peer_challenge, auth_challenge, username, username_len,
131                        challenge);
132         nt_password_hash(password, password_len, password_hash);
133         challenge_response(challenge, password_hash, response);
134 }
135
136
137 /**
138  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
139  * @password: 0-to-256-unicode-char Password (IN)
140  * @password_len: Length of password
141  * @nt_response: 24-octet NT-Response (IN)
142  * @peer_challenge: 16-octet PeerChallenge (IN)
143  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
144  * @username: 0-to-256-char UserName (IN)
145  * @username_len: Length of username
146  * @response: 42-octet AuthenticatorResponse (OUT)
147  */
148 void generate_authenticator_response(const u8 *password, size_t password_len,
149                                      const u8 *peer_challenge,
150                                      const u8 *auth_challenge,
151                                      const u8 *username, size_t username_len,
152                                      const u8 *nt_response, u8 *response)
153 {
154         static const u8 magic1[39] = {
155                 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
156                 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
157                 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
158                 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
159         };
160         static const u8 magic2[41] = {
161                 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
162                 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
163                 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
164                 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
165                 0x6E
166         };
167
168         u8 password_hash[16], password_hash_hash[16], challenge[8];
169         const unsigned char *addr1[3];
170         const size_t len1[3] = { 16, 24, sizeof(magic1) };
171         const unsigned char *addr2[3];
172         const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
173
174         addr1[0] = password_hash_hash;
175         addr1[1] = nt_response;
176         addr1[2] = magic1;
177
178         addr2[0] = response;
179         addr2[1] = challenge;
180         addr2[2] = magic2;
181
182         nt_password_hash(password, password_len, password_hash);
183         hash_nt_password_hash(password_hash, password_hash_hash);
184         sha1_vector(3, addr1, len1, response);
185
186         challenge_hash(peer_challenge, auth_challenge, username, username_len,
187                        challenge);
188         sha1_vector(3, addr2, len2, response);
189 }
190
191
192 /**
193  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
194  * @challenge: 8-octet Challenge (IN)
195  * @password: 0-to-256-unicode-char Password (IN)
196  * @password_len: Length of password
197  * @response: 24-octet Response (OUT)
198  */
199 void nt_challenge_response(const u8 *challenge, const u8 *password,
200                            size_t password_len, u8 *response)
201 {
202         u8 password_hash[16];
203         nt_password_hash(password, password_len, password_hash);
204         challenge_response(challenge, password_hash, response);
205 }
206
207
208 /**
209  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
210  * @password_hash_hash: 16-octet PasswordHashHash (IN)
211  * @nt_response: 24-octet NTResponse (IN)
212  * @master_key: 16-octet MasterKey (OUT)
213  */
214 void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
215                     u8 *master_key)
216 {
217         static const u8 magic1[27] = {
218                 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
219                 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
220                 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
221         };
222         const unsigned char *addr[3];
223         const size_t len[3] = { 16, 24, sizeof(magic1) };
224         u8 hash[SHA1_MAC_LEN];
225
226         addr[0] = password_hash_hash;
227         addr[1] = nt_response;
228         addr[2] = magic1;
229
230         sha1_vector(3, addr, len, hash);
231         memcpy(master_key, hash, 16);
232 }
233
234
235 /**
236  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
237  * @master_key: 16-octet MasterKey (IN)
238  * @session_key: 8-to-16 octet SessionKey (OUT)
239  * @session_key_len: SessionKeyLength (Length of session_key)
240  * @is_send: IsSend (IN, BOOLEAN)
241  * @is_server: IsServer (IN, BOOLEAN)
242  */
243 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
244                              size_t session_key_len, int is_send,
245                              int is_server)
246 {
247         static const u8 magic2[84] = {
248                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
249                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
250                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
251                 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
252                 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
253                 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
254                 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
255                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
256                 0x6b, 0x65, 0x79, 0x2e
257         };
258         static const u8 magic3[84] = {
259                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
260                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
261                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
262                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
263                 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
264                 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
265                 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
266                 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
267                 0x6b, 0x65, 0x79, 0x2e
268         };
269         static const u8 shs_pad1[40] = {
270                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
272                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
273                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
274         };
275
276         static const u8 shs_pad2[40] = {
277                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
278                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
279                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
280                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
281         };
282         u8 digest[SHA1_MAC_LEN];
283         const unsigned char *addr[4];
284         const size_t len[4] = { 16, 40, 84, 40 };
285
286         addr[0] = master_key;
287         addr[1] = shs_pad1;
288         if (is_send) {
289                 addr[2] = is_server ? magic3 : magic2;
290         } else {
291                 addr[2] = is_server ? magic2 : magic3;
292         }
293         addr[3] = shs_pad2;
294
295         sha1_vector(4, addr, len, digest);
296
297         if (session_key_len > SHA1_MAC_LEN)
298                 session_key_len = SHA1_MAC_LEN;
299         memcpy(session_key, digest, session_key_len);
300 }
301
302
303 #define PWBLOCK_LEN 516
304
305 /**
306  * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
307  * @password: 0-to-256-unicode-char Password (IN)
308  * @password_len: Length of password
309  * @password_hash: 16-octet PasswordHash (IN)
310  * @pw_block: 516-byte PwBlock (OUT)
311  */
312 static void encrypt_pw_block_with_password_hash(
313         const u8 *password, size_t password_len,
314         const u8 *password_hash, u8 *pw_block)
315 {
316         size_t i, offset;
317         u8 *pos;
318
319         if (password_len > 256)
320                 return;
321
322         memset(pw_block, 0, PWBLOCK_LEN);
323         offset = (256 - password_len) * 2;
324         for (i = 0; i < password_len; i++)
325                 pw_block[offset + i * 2] = password[i];
326         pos = &pw_block[2 * 256];
327         WPA_PUT_LE16(pos, password_len * 2);
328         rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
329 }
330
331
332 /**
333  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
334  * @new_password: 0-to-256-unicode-char NewPassword (IN)
335  * @new_password_len: Length of new_password
336  * @old_password: 0-to-256-unicode-char OldPassword (IN)
337  * @old_password_len: Length of old_password
338  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
339  */
340 void new_password_encrypted_with_old_nt_password_hash(
341         const u8 *new_password, size_t new_password_len,
342         const u8 *old_password, size_t old_password_len,
343         u8 *encrypted_pw_block)
344 {
345         u8 password_hash[16];
346
347         nt_password_hash(old_password, old_password_len, password_hash);
348         encrypt_pw_block_with_password_hash(new_password, new_password_len,
349                                             password_hash, encrypted_pw_block);
350 }
351
352
353 /**
354  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
355  * @password_hash: 16-octer PasswordHash (IN)
356  * @block: 16-octet Block (IN)
357  * @cypher: 16-octer Cypher (OUT)
358  */
359 static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
360                                                   const u8 *block,
361                                                   u8 *cypher)
362 {
363         des_encrypt(password_hash, block, cypher);
364         des_encrypt(password_hash + 8, block + 7, cypher + 8);
365 }
366
367
368 /**
369  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
370  * @new_password: 0-to-256-unicode-char NewPassword (IN)
371  * @new_password_len: Length of new_password
372  * @old_password: 0-to-256-unicode-char OldPassword (IN)
373  * @old_password_len: Length of old_password
374  * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
375  */
376 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
377         const u8 *new_password, size_t new_password_len,
378         const u8 *old_password, size_t old_password_len,
379         u8 *encrypted_password_hash)
380 {
381         u8 old_password_hash[16], new_password_hash[16];
382
383         nt_password_hash(old_password, old_password_len, old_password_hash);
384         nt_password_hash(new_password, new_password_len, new_password_hash);
385         nt_password_hash_encrypted_with_block(old_password_hash,
386                                               new_password_hash,
387                                               encrypted_password_hash);
388 }
389
390
391 #ifdef TEST_MAIN_MS_FUNCS
392
393 #include "rc4.c"
394
395 int main(int argc, char *argv[])
396 {
397         /* Test vector from RFC2759 example */
398         u8 *username = "User";
399         u8 *password = "clientPass";
400         u8 auth_challenge[] = {
401                 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
402                 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
403         };
404         u8 peer_challenge[] = {
405                 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
406                 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
407         };
408         u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
409         u8 password_hash[] = {
410                 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
411                 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
412         };
413         u8 nt_response[] = {
414                 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
415                 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
416                 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
417         };
418         u8 password_hash_hash[] = {
419                 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
420                 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
421         };
422         u8 authenticator_response[] = {
423                 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
424                 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
425                 0x93, 0x2C, 0xDA, 0x56
426         };
427         u8 master_key[] = {
428                 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
429                 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
430         };
431         u8 send_start_key[] = {
432                 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
433                 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
434         };
435         u8 buf[32];
436
437         int errors = 0;
438
439         printf("Testing ms_funcs.c\n");
440
441         challenge_hash(peer_challenge, auth_challenge,
442                        username, strlen(username),
443                        buf);
444         if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
445                 printf("challenge_hash failed\n");
446                 errors++;
447         }
448
449         nt_password_hash(password, strlen(password), buf);
450         if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
451                 printf("nt_password_hash failed\n");
452                 errors++;
453         }
454
455         generate_nt_response(auth_challenge, peer_challenge,
456                              username, strlen(username),
457                              password, strlen(password),
458                              buf);
459         if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
460                 printf("generate_nt_response failed\n");
461                 errors++;
462         }
463
464         hash_nt_password_hash(password_hash, buf);
465         if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
466                 printf("hash_nt_password_hash failed\n");
467                 errors++;
468         }
469
470         generate_authenticator_response(password, strlen(password),
471                                         peer_challenge, auth_challenge,
472                                         username, strlen(username),
473                                         nt_response, buf);
474         if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
475             != 0) {
476                 printf("generate_authenticator_response failed\n");
477                 errors++;
478         }
479
480         get_master_key(password_hash_hash, nt_response, buf);
481         if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
482                 printf("get_master_key failed\n");
483                 errors++;
484         }
485
486         get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
487         if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
488                 printf("get_asymetric_start_key failed\n");
489                 errors++;
490         }
491
492         if (errors)
493                 printf("FAILED! %d errors\n", errors);
494
495         return errors;
496 }
497 #endif /* TEST_MAIN_MS_FUNCS */