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 */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)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 */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)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 */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)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 */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)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 */
generate_nt_response(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password,size_t password_len,u8 * response)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 */
generate_nt_response_pwhash(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password_hash,u8 * response)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 */
generate_authenticator_response_pwhash(const u8 * password_hash,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)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 */
generate_authenticator_response(const u8 * password,size_t password_len,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)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 */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)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 */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)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 */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)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 */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)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 */
new_password_encrypted_with_old_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_pw_block)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 */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)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 */
old_nt_password_hash_encrypted_with_new_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_password_hash)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 }
447