2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.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.
24 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
25 * @peer_challenge: 16-octet PeerChallenge (IN)
26 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
27 * @username: 0-to-256-char UserName (IN)
28 * @username_len: Length of username
29 * @challenge: 8-octet Challenge (OUT)
30 * Returns: 0 on success, -1 on failure
32 static int challenge_hash(const u8
*peer_challenge
, const u8
*auth_challenge
,
33 const u8
*username
, size_t username_len
,
36 u8 hash
[SHA1_MAC_LEN
];
37 const unsigned char *addr
[3];
40 addr
[0] = peer_challenge
;
42 addr
[1] = auth_challenge
;
45 len
[2] = username_len
;
47 if (sha1_vector(3, addr
, len
, hash
))
49 os_memcpy(challenge
, hash
, 8);
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)
59 * Returns: 0 on success, -1 on failure
61 int nt_password_hash(const u8
*password
, size_t password_len
,
67 if (password_len
> 256)
70 /* Convert password into unicode */
71 for (i
= 0; i
< password_len
; i
++) {
72 buf
[2 * i
] = password
[i
];
76 len
= password_len
* 2;
78 return md4_vector(1, (const u8
**) &pos
, &len
, password_hash
);
83 * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
84 * @password_hash: 16-octet PasswordHash (IN)
85 * @password_hash_hash: 16-octet PasswordHashHash (OUT)
86 * Returns: 0 on success, -1 on failure
88 int hash_nt_password_hash(const u8
*password_hash
, u8
*password_hash_hash
)
91 return md4_vector(1, &password_hash
, &len
, password_hash_hash
);
96 * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
97 * @challenge: 8-octet Challenge (IN)
98 * @password_hash: 16-octet PasswordHash (IN)
99 * @response: 24-octet Response (OUT)
101 void challenge_response(const u8
*challenge
, const u8
*password_hash
,
105 des_encrypt(challenge
, password_hash
, response
);
106 des_encrypt(challenge
, password_hash
+ 7, response
+ 8);
107 zpwd
[0] = password_hash
[14];
108 zpwd
[1] = password_hash
[15];
109 os_memset(zpwd
+ 2, 0, 5);
110 des_encrypt(challenge
, zpwd
, response
+ 16);
115 * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
116 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
117 * @peer_challenge: 16-octet PeerChallenge (IN)
118 * @username: 0-to-256-char UserName (IN)
119 * @username_len: Length of username
120 * @password: 0-to-256-unicode-char Password (IN; ASCII)
121 * @password_len: Length of password
122 * @response: 24-octet Response (OUT)
123 * Returns: 0 on success, -1 on failure
125 int generate_nt_response(const u8
*auth_challenge
, const u8
*peer_challenge
,
126 const u8
*username
, size_t username_len
,
127 const u8
*password
, size_t password_len
,
131 u8 password_hash
[16];
133 challenge_hash(peer_challenge
, auth_challenge
, username
, username_len
,
135 if (nt_password_hash(password
, password_len
, password_hash
))
137 challenge_response(challenge
, password_hash
, response
);
143 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
144 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
145 * @peer_challenge: 16-octet PeerChallenge (IN)
146 * @username: 0-to-256-char UserName (IN)
147 * @username_len: Length of username
148 * @password_hash: 16-octet PasswordHash (IN)
149 * @response: 24-octet Response (OUT)
150 * Returns: 0 on success, -1 on failure
152 int generate_nt_response_pwhash(const u8
*auth_challenge
,
153 const u8
*peer_challenge
,
154 const u8
*username
, size_t username_len
,
155 const u8
*password_hash
,
160 if (challenge_hash(peer_challenge
, auth_challenge
,
161 username
, username_len
,
164 challenge_response(challenge
, password_hash
, response
);
170 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
171 * @password_hash: 16-octet PasswordHash (IN)
172 * @nt_response: 24-octet NT-Response (IN)
173 * @peer_challenge: 16-octet PeerChallenge (IN)
174 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
175 * @username: 0-to-256-char UserName (IN)
176 * @username_len: Length of username
177 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
178 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
179 * Returns: 0 on success, -1 on failure
181 int generate_authenticator_response_pwhash(
182 const u8
*password_hash
,
183 const u8
*peer_challenge
, const u8
*auth_challenge
,
184 const u8
*username
, size_t username_len
,
185 const u8
*nt_response
, u8
*response
)
187 static const u8 magic1
[39] = {
188 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
189 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
190 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
191 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
193 static const u8 magic2
[41] = {
194 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
195 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
196 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
197 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
201 u8 password_hash_hash
[16], challenge
[8];
202 const unsigned char *addr1
[3];
203 const size_t len1
[3] = { 16, 24, sizeof(magic1
) };
204 const unsigned char *addr2
[3];
205 const size_t len2
[3] = { SHA1_MAC_LEN
, 8, sizeof(magic2
) };
207 addr1
[0] = password_hash_hash
;
208 addr1
[1] = nt_response
;
212 addr2
[1] = challenge
;
215 if (hash_nt_password_hash(password_hash
, password_hash_hash
))
217 if (sha1_vector(3, addr1
, len1
, response
))
220 challenge_hash(peer_challenge
, auth_challenge
, username
, username_len
,
222 return sha1_vector(3, addr2
, len2
, response
);
227 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
228 * @password: 0-to-256-unicode-char Password (IN; ASCII)
229 * @password_len: Length of password
230 * @nt_response: 24-octet NT-Response (IN)
231 * @peer_challenge: 16-octet PeerChallenge (IN)
232 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
233 * @username: 0-to-256-char UserName (IN)
234 * @username_len: Length of username
235 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
236 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
237 * Returns: 0 on success, -1 on failure
239 int generate_authenticator_response(const u8
*password
, size_t password_len
,
240 const u8
*peer_challenge
,
241 const u8
*auth_challenge
,
242 const u8
*username
, size_t username_len
,
243 const u8
*nt_response
, u8
*response
)
245 u8 password_hash
[16];
246 if (nt_password_hash(password
, password_len
, password_hash
))
248 return generate_authenticator_response_pwhash(
249 password_hash
, peer_challenge
, auth_challenge
,
250 username
, username_len
, nt_response
, response
);
255 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
256 * @challenge: 8-octet Challenge (IN)
257 * @password: 0-to-256-unicode-char Password (IN; ASCII)
258 * @password_len: Length of password
259 * @response: 24-octet Response (OUT)
260 * Returns: 0 on success, -1 on failure
262 int nt_challenge_response(const u8
*challenge
, const u8
*password
,
263 size_t password_len
, u8
*response
)
265 u8 password_hash
[16];
266 if (nt_password_hash(password
, password_len
, password_hash
))
268 challenge_response(challenge
, password_hash
, response
);
274 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
275 * @password_hash_hash: 16-octet PasswordHashHash (IN)
276 * @nt_response: 24-octet NTResponse (IN)
277 * @master_key: 16-octet MasterKey (OUT)
278 * Returns: 0 on success, -1 on failure
280 int get_master_key(const u8
*password_hash_hash
, const u8
*nt_response
,
283 static const u8 magic1
[27] = {
284 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
285 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
286 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
288 const unsigned char *addr
[3];
289 const size_t len
[3] = { 16, 24, sizeof(magic1
) };
290 u8 hash
[SHA1_MAC_LEN
];
292 addr
[0] = password_hash_hash
;
293 addr
[1] = nt_response
;
296 if (sha1_vector(3, addr
, len
, hash
))
298 os_memcpy(master_key
, hash
, 16);
304 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
305 * @master_key: 16-octet MasterKey (IN)
306 * @session_key: 8-to-16 octet SessionKey (OUT)
307 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
308 * @is_send: IsSend (IN, BOOLEAN)
309 * @is_server: IsServer (IN, BOOLEAN)
310 * Returns: 0 on success, -1 on failure
312 int get_asymetric_start_key(const u8
*master_key
, u8
*session_key
,
313 size_t session_key_len
, int is_send
,
316 static const u8 magic2
[84] = {
317 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
318 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
319 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
320 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
321 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
322 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
323 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
324 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
325 0x6b, 0x65, 0x79, 0x2e
327 static const u8 magic3
[84] = {
328 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
329 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
330 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
331 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
332 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
333 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
334 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
335 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
336 0x6b, 0x65, 0x79, 0x2e
338 static const u8 shs_pad1
[40] = {
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
345 static const u8 shs_pad2
[40] = {
346 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
347 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
348 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
349 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
351 u8 digest
[SHA1_MAC_LEN
];
352 const unsigned char *addr
[4];
353 const size_t len
[4] = { 16, 40, 84, 40 };
355 addr
[0] = master_key
;
358 addr
[2] = is_server
? magic3
: magic2
;
360 addr
[2] = is_server
? magic2
: magic3
;
364 if (sha1_vector(4, addr
, len
, digest
))
367 if (session_key_len
> SHA1_MAC_LEN
)
368 session_key_len
= SHA1_MAC_LEN
;
369 os_memcpy(session_key
, digest
, session_key_len
);
374 #define PWBLOCK_LEN 516
377 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
378 * @password: 0-to-256-unicode-char Password (IN; ASCII)
379 * @password_len: Length of password
380 * @password_hash: 16-octet PasswordHash (IN)
381 * @pw_block: 516-byte PwBlock (OUT)
382 * Returns: 0 on success, -1 on failure
384 int encrypt_pw_block_with_password_hash(
385 const u8
*password
, size_t password_len
,
386 const u8
*password_hash
, u8
*pw_block
)
391 if (password_len
> 256)
394 os_memset(pw_block
, 0, PWBLOCK_LEN
);
395 offset
= (256 - password_len
) * 2;
396 if (os_get_random(pw_block
, offset
) < 0)
398 for (i
= 0; i
< password_len
; i
++)
399 pw_block
[offset
+ i
* 2] = password
[i
];
401 * PasswordLength is 4 octets, but since the maximum password length is
402 * 256, only first two (in little endian byte order) can be non-zero.
404 pos
= &pw_block
[2 * 256];
405 WPA_PUT_LE16(pos
, password_len
* 2);
406 rc4_skip(password_hash
, 16, 0, pw_block
, PWBLOCK_LEN
);
412 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
413 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
414 * @new_password_len: Length of new_password
415 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
416 * @old_password_len: Length of old_password
417 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
418 * Returns: 0 on success, -1 on failure
420 int new_password_encrypted_with_old_nt_password_hash(
421 const u8
*new_password
, size_t new_password_len
,
422 const u8
*old_password
, size_t old_password_len
,
423 u8
*encrypted_pw_block
)
425 u8 password_hash
[16];
427 if (nt_password_hash(old_password
, old_password_len
, password_hash
))
429 if (encrypt_pw_block_with_password_hash(new_password
, new_password_len
,
438 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
439 * @password_hash: 16-octer PasswordHash (IN)
440 * @block: 16-octet Block (IN)
441 * @cypher: 16-octer Cypher (OUT)
443 void nt_password_hash_encrypted_with_block(const u8
*password_hash
,
444 const u8
*block
, u8
*cypher
)
446 des_encrypt(password_hash
, block
, cypher
);
447 des_encrypt(password_hash
+ 8, block
+ 7, cypher
+ 8);
452 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
453 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
454 * @new_password_len: Length of new_password
455 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
456 * @old_password_len: Length of old_password
457 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
458 * Returns: 0 on success, -1 on failure
460 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
461 const u8
*new_password
, size_t new_password_len
,
462 const u8
*old_password
, size_t old_password_len
,
463 u8
*encrypted_password_hash
)
465 u8 old_password_hash
[16], new_password_hash
[16];
467 if (nt_password_hash(old_password
, old_password_len
,
468 old_password_hash
) ||
469 nt_password_hash(new_password
, new_password_len
,
472 nt_password_hash_encrypted_with_block(old_password_hash
,
474 encrypted_password_hash
);