If there is no commitid, we need to initialize Delta->commitid to NULL to
[dragonfly.git] / contrib / wpa_supplicant-0.4.9 / ms_funcs.c
bloba72cf274812d902b5761d7312863f689d36f155b
1 /*
2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3 * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
19 #include "common.h"
20 #include "sha1.h"
21 #include "ms_funcs.h"
22 #include "crypto.h"
23 #include "rc4.h"
26 /**
27 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
28 * @peer_challenge: 16-octet PeerChallenge (IN)
29 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
30 * @username: 0-to-256-char UserName (IN)
31 * @username_len: Length of username
32 * @challenge: 8-octet Challenge (OUT)
34 static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
35 const u8 *username, size_t username_len,
36 u8 *challenge)
38 u8 hash[SHA1_MAC_LEN];
39 const unsigned char *addr[3];
40 size_t len[3];
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;
49 sha1_vector(3, addr, len, hash);
50 memcpy(challenge, hash, 8);
54 /**
55 * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
56 * @password: 0-to-256-unicode-char Password (IN; ASCII)
57 * @password_len: Length of password
58 * @password_hash: 16-octet PasswordHash (OUT)
60 void nt_password_hash(const u8 *password, size_t password_len,
61 u8 *password_hash)
63 u8 buf[512], *pos;
64 size_t i, len;
66 if (password_len > 256)
67 return;
69 /* Convert password into unicode */
70 for (i = 0; i < password_len; i++) {
71 buf[2 * i] = password[i];
72 buf[2 * i + 1] = 0;
75 len = password_len * 2;
76 pos = buf;
77 md4_vector(1, (const u8 **) &pos, &len, password_hash);
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 PasswordHashHash (OUT)
86 void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
88 size_t len = 16;
89 md4_vector(1, &password_hash, &len, password_hash_hash);
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)
99 void challenge_response(const u8 *challenge, const u8 *password_hash,
100 u8 *response)
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);
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; ASCII)
119 * @password_len: Length of password
120 * @response: 24-octet Response (OUT)
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)
127 u8 challenge[8];
128 u8 password_hash[16];
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);
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: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
147 * encoded as a 42-octet ASCII string (S=<hexdump of response>)
149 void generate_authenticator_response(const u8 *password, size_t password_len,
150 const u8 *peer_challenge,
151 const u8 *auth_challenge,
152 const u8 *username, size_t username_len,
153 const u8 *nt_response, u8 *response)
155 static const u8 magic1[39] = {
156 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
157 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
158 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
159 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
161 static const u8 magic2[41] = {
162 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
163 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
164 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
165 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
166 0x6E
169 u8 password_hash[16], password_hash_hash[16], challenge[8];
170 const unsigned char *addr1[3];
171 const size_t len1[3] = { 16, 24, sizeof(magic1) };
172 const unsigned char *addr2[3];
173 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
175 addr1[0] = password_hash_hash;
176 addr1[1] = nt_response;
177 addr1[2] = magic1;
179 addr2[0] = response;
180 addr2[1] = challenge;
181 addr2[2] = magic2;
183 nt_password_hash(password, password_len, password_hash);
184 hash_nt_password_hash(password_hash, password_hash_hash);
185 sha1_vector(3, addr1, len1, response);
187 challenge_hash(peer_challenge, auth_challenge, username, username_len,
188 challenge);
189 sha1_vector(3, addr2, len2, response);
194 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
195 * @challenge: 8-octet Challenge (IN)
196 * @password: 0-to-256-unicode-char Password (IN; ASCII)
197 * @password_len: Length of password
198 * @response: 24-octet Response (OUT)
200 void nt_challenge_response(const u8 *challenge, const u8 *password,
201 size_t password_len, u8 *response)
203 u8 password_hash[16];
204 nt_password_hash(password, password_len, password_hash);
205 challenge_response(challenge, password_hash, response);
210 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
211 * @password_hash_hash: 16-octet PasswordHashHash (IN)
212 * @nt_response: 24-octet NTResponse (IN)
213 * @master_key: 16-octet MasterKey (OUT)
215 void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
216 u8 *master_key)
218 static const u8 magic1[27] = {
219 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
220 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
221 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
223 const unsigned char *addr[3];
224 const size_t len[3] = { 16, 24, sizeof(magic1) };
225 u8 hash[SHA1_MAC_LEN];
227 addr[0] = password_hash_hash;
228 addr[1] = nt_response;
229 addr[2] = magic1;
231 sha1_vector(3, addr, len, hash);
232 memcpy(master_key, hash, 16);
237 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
238 * @master_key: 16-octet MasterKey (IN)
239 * @session_key: 8-to-16 octet SessionKey (OUT)
240 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
241 * @is_send: IsSend (IN, BOOLEAN)
242 * @is_server: IsServer (IN, BOOLEAN)
244 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
245 size_t session_key_len, int is_send,
246 int is_server)
248 static const u8 magic2[84] = {
249 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
250 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
251 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
252 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
253 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
254 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
255 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
256 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
257 0x6b, 0x65, 0x79, 0x2e
259 static const u8 magic3[84] = {
260 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
261 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
262 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
263 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
264 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
265 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
266 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
267 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
268 0x6b, 0x65, 0x79, 0x2e
270 static const u8 shs_pad1[40] = {
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
277 static const u8 shs_pad2[40] = {
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 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
283 u8 digest[SHA1_MAC_LEN];
284 const unsigned char *addr[4];
285 const size_t len[4] = { 16, 40, 84, 40 };
287 addr[0] = master_key;
288 addr[1] = shs_pad1;
289 if (is_send) {
290 addr[2] = is_server ? magic3 : magic2;
291 } else {
292 addr[2] = is_server ? magic2 : magic3;
294 addr[3] = shs_pad2;
296 sha1_vector(4, addr, len, digest);
298 if (session_key_len > SHA1_MAC_LEN)
299 session_key_len = SHA1_MAC_LEN;
300 memcpy(session_key, digest, session_key_len);
304 #define PWBLOCK_LEN 516
307 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
308 * @password: 0-to-256-unicode-char Password (IN; ASCII)
309 * @password_len: Length of password
310 * @password_hash: 16-octet PasswordHash (IN)
311 * @pw_block: 516-byte PwBlock (OUT)
313 static void encrypt_pw_block_with_password_hash(
314 const u8 *password, size_t password_len,
315 const u8 *password_hash, u8 *pw_block)
317 size_t i, offset;
318 u8 *pos;
320 if (password_len > 256)
321 return;
323 memset(pw_block, 0, PWBLOCK_LEN);
324 offset = (256 - password_len) * 2;
325 hostapd_get_rand(pw_block, offset);
326 for (i = 0; i < password_len; i++)
327 pw_block[offset + i * 2] = password[i];
329 * PasswordLength is 4 octets, but since the maximum password length is
330 * 256, only first two (in little endian byte order) can be non-zero.
332 pos = &pw_block[2 * 256];
333 WPA_PUT_LE16(pos, password_len * 2);
334 rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
339 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
340 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
341 * @new_password_len: Length of new_password
342 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
343 * @old_password_len: Length of old_password
344 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
346 void new_password_encrypted_with_old_nt_password_hash(
347 const u8 *new_password, size_t new_password_len,
348 const u8 *old_password, size_t old_password_len,
349 u8 *encrypted_pw_block)
351 u8 password_hash[16];
353 nt_password_hash(old_password, old_password_len, password_hash);
354 encrypt_pw_block_with_password_hash(new_password, new_password_len,
355 password_hash, encrypted_pw_block);
360 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
361 * @password_hash: 16-octer PasswordHash (IN)
362 * @block: 16-octet Block (IN)
363 * @cypher: 16-octer Cypher (OUT)
365 static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
366 const u8 *block,
367 u8 *cypher)
369 des_encrypt(password_hash, block, cypher);
370 des_encrypt(password_hash + 8, block + 7, cypher + 8);
375 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
376 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
377 * @new_password_len: Length of new_password
378 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
379 * @old_password_len: Length of old_password
380 * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
382 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
383 const u8 *new_password, size_t new_password_len,
384 const u8 *old_password, size_t old_password_len,
385 u8 *encrypted_password_hash)
387 u8 old_password_hash[16], new_password_hash[16];
389 nt_password_hash(old_password, old_password_len, old_password_hash);
390 nt_password_hash(new_password, new_password_len, new_password_hash);
391 nt_password_hash_encrypted_with_block(old_password_hash,
392 new_password_hash,
393 encrypted_password_hash);
397 #ifdef TEST_MAIN_MS_FUNCS
399 #include "rc4.c"
401 int main(int argc, char *argv[])
403 /* Test vector from RFC2759 example */
404 u8 *username = "User";
405 u8 *password = "clientPass";
406 u8 auth_challenge[] = {
407 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
408 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
410 u8 peer_challenge[] = {
411 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
412 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
414 u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
415 u8 password_hash[] = {
416 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
417 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
419 u8 nt_response[] = {
420 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
421 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
422 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
424 u8 password_hash_hash[] = {
425 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
426 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
428 u8 authenticator_response[] = {
429 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
430 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
431 0x93, 0x2C, 0xDA, 0x56
433 u8 master_key[] = {
434 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
435 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
437 u8 send_start_key[] = {
438 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
439 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
441 u8 buf[32];
443 int errors = 0;
445 printf("Testing ms_funcs.c\n");
447 challenge_hash(peer_challenge, auth_challenge,
448 username, strlen(username),
449 buf);
450 if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
451 printf("challenge_hash failed\n");
452 errors++;
455 nt_password_hash(password, strlen(password), buf);
456 if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
457 printf("nt_password_hash failed\n");
458 errors++;
461 generate_nt_response(auth_challenge, peer_challenge,
462 username, strlen(username),
463 password, strlen(password),
464 buf);
465 if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
466 printf("generate_nt_response failed\n");
467 errors++;
470 hash_nt_password_hash(password_hash, buf);
471 if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
472 printf("hash_nt_password_hash failed\n");
473 errors++;
476 generate_authenticator_response(password, strlen(password),
477 peer_challenge, auth_challenge,
478 username, strlen(username),
479 nt_response, buf);
480 if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
481 != 0) {
482 printf("generate_authenticator_response failed\n");
483 errors++;
486 get_master_key(password_hash_hash, nt_response, buf);
487 if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
488 printf("get_master_key failed\n");
489 errors++;
492 get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
493 if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
494 printf("get_asymetric_start_key failed\n");
495 errors++;
498 if (errors)
499 printf("FAILED! %d errors\n", errors);
501 return errors;
503 #endif /* TEST_MAIN_MS_FUNCS */