2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3 * Copyright (c) 2004-2005, 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
12 * See README and COPYING for more details.
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)
34 static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
35 const u8 *username, size_t username_len,
38 u8 hash[SHA1_MAC_LEN];
39 const unsigned char *addr[3];
42 addr[0] = peer_challenge;
44 addr[1] = auth_challenge;
47 len[2] = username_len;
49 sha1_vector(3, addr, len, hash);
50 memcpy(challenge, hash, 8);
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)
60 void nt_password_hash(const u8 *password, size_t password_len,
67 /* Convert password into unicode */
68 buf = malloc(password_len * 2);
71 memset(buf, 0, password_len * 2);
72 for (i = 0; i < password_len; i++)
73 buf[2 * i] = password[i];
75 len = password_len * 2;
76 md4_vector(1, (const u8 **) &buf, &len, password_hash);
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)
86 void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
89 md4_vector(1, &password_hash, &len, password_hash_hash);
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,
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)
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,
128 u8 password_hash[16];
130 challenge_hash(peer_challenge, auth_challenge, username, username_len,
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: 42-octet AuthenticatorResponse (OUT)
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)
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
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,
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) };
174 addr1[0] = password_hash_hash;
175 addr1[1] = nt_response;
179 addr2[1] = challenge;
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);
186 challenge_hash(peer_challenge, auth_challenge, username, username_len,
188 sha1_vector(3, addr2, len2, response);
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)
199 void nt_challenge_response(const u8 *challenge, const u8 *password,
200 size_t password_len, u8 *response)
202 u8 password_hash[16];
203 nt_password_hash(password, password_len, password_hash);
204 challenge_response(challenge, password_hash, response);
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)
214 void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
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
222 const unsigned char *addr[3];
223 const size_t len[3] = { 16, 24, sizeof(magic1) };
224 u8 hash[SHA1_MAC_LEN];
226 addr[0] = password_hash_hash;
227 addr[1] = nt_response;
230 sha1_vector(3, addr, len, hash);
231 memcpy(master_key, hash, 16);
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)
243 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
244 size_t session_key_len, int is_send,
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
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
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
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
282 u8 digest[SHA1_MAC_LEN];
283 const unsigned char *addr[4];
284 const size_t len[4] = { 16, 40, 84, 40 };
286 addr[0] = master_key;
289 addr[2] = is_server ? magic3 : magic2;
291 addr[2] = is_server ? magic2 : magic3;
295 sha1_vector(4, addr, len, digest);
297 if (session_key_len > SHA1_MAC_LEN)
298 session_key_len = SHA1_MAC_LEN;
299 memcpy(session_key, digest, session_key_len);
303 #define PWBLOCK_LEN 516
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)
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)
319 if (password_len > 256)
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);
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)
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)
345 u8 password_hash[16];
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);
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)
359 static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
363 des_encrypt(password_hash, block, cypher);
364 des_encrypt(password_hash + 8, block + 7, cypher + 8);
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)
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)
381 u8 old_password_hash[16], new_password_hash[16];
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,
387 encrypted_password_hash);
391 #ifdef TEST_MAIN_MS_FUNCS
395 int main(int argc, char *argv[])
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
404 u8 peer_challenge[] = {
405 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
406 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
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
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
418 u8 password_hash_hash[] = {
419 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
420 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
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
428 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
429 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
431 u8 send_start_key[] = {
432 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
433 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
439 printf("Testing ms_funcs.c\n");
441 challenge_hash(peer_challenge, auth_challenge,
442 username, strlen(username),
444 if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
445 printf("challenge_hash failed\n");
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");
455 generate_nt_response(auth_challenge, peer_challenge,
456 username, strlen(username),
457 password, strlen(password),
459 if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
460 printf("generate_nt_response failed\n");
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");
470 generate_authenticator_response(password, strlen(password),
471 peer_challenge, auth_challenge,
472 username, strlen(username),
474 if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
476 printf("generate_authenticator_response failed\n");
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");
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");
493 printf("FAILED! %d errors\n", errors);
497 #endif /* TEST_MAIN_MS_FUNCS */