xref: /freebsd/contrib/wpa/src/crypto/ms_funcs.c (revision eef8b03ca023b906cef9f8b85212e61ae9d95d0b)
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2009, 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 
22 
23 /**
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
31  */
32 static int 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 	if (sha1_vector(3, addr, len, hash))
48 		return -1;
49 	os_memcpy(challenge, hash, 8);
50 	return 0;
51 }
52 
53 
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)
59  * Returns: 0 on success, -1 on failure
60  */
61 int nt_password_hash(const u8 *password, size_t password_len,
62 		      u8 *password_hash)
63 {
64 	u8 buf[512], *pos;
65 	size_t i, len;
66 
67 	if (password_len > 256)
68 		password_len = 256;
69 
70 	/* Convert password into unicode */
71 	for (i = 0; i < password_len; i++) {
72 		buf[2 * i] = password[i];
73 		buf[2 * i + 1] = 0;
74 	}
75 
76 	len = password_len * 2;
77 	pos = buf;
78 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
79 }
80 
81 
82 /**
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
87  */
88 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
89 {
90 	size_t len = 16;
91 	return md4_vector(1, &password_hash, &len, password_hash_hash);
92 }
93 
94 
95 /**
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)
100  */
101 void challenge_response(const u8 *challenge, const u8 *password_hash,
102 			u8 *response)
103 {
104 	u8 zpwd[7];
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);
111 }
112 
113 
114 /**
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
124  */
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,
128 			 u8 *response)
129 {
130 	u8 challenge[8];
131 	u8 password_hash[16];
132 
133 	challenge_hash(peer_challenge, auth_challenge, username, username_len,
134 		       challenge);
135 	if (nt_password_hash(password, password_len, password_hash))
136 		return -1;
137 	challenge_response(challenge, password_hash, response);
138 	return 0;
139 }
140 
141 
142 /**
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
151  */
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,
156 				u8 *response)
157 {
158 	u8 challenge[8];
159 
160 	if (challenge_hash(peer_challenge, auth_challenge,
161 			   username, username_len,
162 			   challenge))
163 		return -1;
164 	challenge_response(challenge, password_hash, response);
165 	return 0;
166 }
167 
168 
169 /**
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
180  */
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)
186 {
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
192 	};
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,
198 		0x6E
199 	};
200 
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) };
206 
207 	addr1[0] = password_hash_hash;
208 	addr1[1] = nt_response;
209 	addr1[2] = magic1;
210 
211 	addr2[0] = response;
212 	addr2[1] = challenge;
213 	addr2[2] = magic2;
214 
215 	if (hash_nt_password_hash(password_hash, password_hash_hash))
216 		return -1;
217 	if (sha1_vector(3, addr1, len1, response))
218 		return -1;
219 
220 	challenge_hash(peer_challenge, auth_challenge, username, username_len,
221 		       challenge);
222 	return sha1_vector(3, addr2, len2, response);
223 }
224 
225 
226 /**
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
238  */
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)
244 {
245 	u8 password_hash[16];
246 	if (nt_password_hash(password, password_len, password_hash))
247 		return -1;
248 	return generate_authenticator_response_pwhash(
249 		password_hash, peer_challenge, auth_challenge,
250 		username, username_len, nt_response, response);
251 }
252 
253 
254 /**
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
261  */
262 int nt_challenge_response(const u8 *challenge, const u8 *password,
263 			  size_t password_len, u8 *response)
264 {
265 	u8 password_hash[16];
266 	if (nt_password_hash(password, password_len, password_hash))
267 		return -1;
268 	challenge_response(challenge, password_hash, response);
269 	return 0;
270 }
271 
272 
273 /**
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
279  */
280 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
281 		   u8 *master_key)
282 {
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
287 	};
288 	const unsigned char *addr[3];
289 	const size_t len[3] = { 16, 24, sizeof(magic1) };
290 	u8 hash[SHA1_MAC_LEN];
291 
292 	addr[0] = password_hash_hash;
293 	addr[1] = nt_response;
294 	addr[2] = magic1;
295 
296 	if (sha1_vector(3, addr, len, hash))
297 		return -1;
298 	os_memcpy(master_key, hash, 16);
299 	return 0;
300 }
301 
302 
303 /**
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
311  */
312 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
313 			    size_t session_key_len, int is_send,
314 			    int is_server)
315 {
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
326 	};
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
337 	};
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
343 	};
344 
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
350 	};
351 	u8 digest[SHA1_MAC_LEN];
352 	const unsigned char *addr[4];
353 	const size_t len[4] = { 16, 40, 84, 40 };
354 
355 	addr[0] = master_key;
356 	addr[1] = shs_pad1;
357 	if (is_send) {
358 		addr[2] = is_server ? magic3 : magic2;
359 	} else {
360 		addr[2] = is_server ? magic2 : magic3;
361 	}
362 	addr[3] = shs_pad2;
363 
364 	if (sha1_vector(4, addr, len, digest))
365 		return -1;
366 
367 	if (session_key_len > SHA1_MAC_LEN)
368 		session_key_len = SHA1_MAC_LEN;
369 	os_memcpy(session_key, digest, session_key_len);
370 	return 0;
371 }
372 
373 
374 #define PWBLOCK_LEN 516
375 
376 /**
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
383  */
384 int encrypt_pw_block_with_password_hash(
385 	const u8 *password, size_t password_len,
386 	const u8 *password_hash, u8 *pw_block)
387 {
388 	size_t i, offset;
389 	u8 *pos;
390 
391 	if (password_len > 256)
392 		return -1;
393 
394 	os_memset(pw_block, 0, PWBLOCK_LEN);
395 	offset = (256 - password_len) * 2;
396 	if (os_get_random(pw_block, offset) < 0)
397 		return -1;
398 	for (i = 0; i < password_len; i++)
399 		pw_block[offset + i * 2] = password[i];
400 	/*
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.
403 	 */
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);
407 	return 0;
408 }
409 
410 
411 /**
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
419  */
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)
424 {
425 	u8 password_hash[16];
426 
427 	if (nt_password_hash(old_password, old_password_len, password_hash))
428 		return -1;
429 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
430 						password_hash,
431 						encrypted_pw_block))
432 		return -1;
433 	return 0;
434 }
435 
436 
437 /**
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)
442  */
443 void nt_password_hash_encrypted_with_block(const u8 *password_hash,
444 					   const u8 *block, u8 *cypher)
445 {
446 	des_encrypt(password_hash, block, cypher);
447 	des_encrypt(password_hash + 8, block + 7, cypher + 8);
448 }
449 
450 
451 /**
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
459  */
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)
464 {
465 	u8 old_password_hash[16], new_password_hash[16];
466 
467 	if (nt_password_hash(old_password, old_password_len,
468 			     old_password_hash) ||
469 	    nt_password_hash(new_password, new_password_len,
470 			     new_password_hash))
471 		return -1;
472 	nt_password_hash_encrypted_with_block(old_password_hash,
473 					      new_password_hash,
474 					      encrypted_password_hash);
475 	return 0;
476 }
477