xref: /freebsd/contrib/wpa/src/crypto/ms_funcs.c (revision 6ba2210ee039f2f12878c217bcf058e9c8b26b29)
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "sha1.h"
13 #include "ms_funcs.h"
14 #include "crypto.h"
15 
16 /**
17  * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18  * @utf8_string: UTF-8 string (IN)
19  * @utf8_string_len: Length of utf8_string (IN)
20  * @ucs2_buffer: UCS-2 buffer (OUT)
21  * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
22  * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
23  * Returns: 0 on success, -1 on failure
24  */
25 static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
26                         u8 *ucs2_buffer, size_t ucs2_buffer_size,
27                         size_t *ucs2_string_size)
28 {
29 	size_t i, j;
30 
31 	for (i = 0, j = 0; i < utf8_string_len; i++) {
32 		u8 c = utf8_string[i];
33 		if (j >= ucs2_buffer_size) {
34 			/* input too long */
35 			return -1;
36 		}
37 		if (c <= 0x7F) {
38 			WPA_PUT_LE16(ucs2_buffer + j, c);
39 			j += 2;
40 		} else if (i == utf8_string_len - 1 ||
41 			   j >= ucs2_buffer_size - 1) {
42 			/* incomplete surrogate */
43 			return -1;
44 		} else {
45 			u8 c2 = utf8_string[++i];
46 			if ((c & 0xE0) == 0xC0) {
47 				/* two-byte encoding */
48 				WPA_PUT_LE16(ucs2_buffer + j,
49 					     ((c & 0x1F) << 6) | (c2 & 0x3F));
50 				j += 2;
51 			} else if (i == utf8_string_len - 1 ||
52 				   j >= ucs2_buffer_size - 1) {
53 				/* incomplete surrogate */
54 				return -1;
55 			} else {
56 				/* three-byte encoding */
57 				u8 c3 = utf8_string[++i];
58 				WPA_PUT_LE16(ucs2_buffer + j,
59 					     ((c & 0xF) << 12) |
60 					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
61 				j += 2;
62 			}
63 		}
64 	}
65 
66 	if (ucs2_string_size)
67 		*ucs2_string_size = j / 2;
68 	return 0;
69 }
70 
71 
72 /**
73  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
74  * @peer_challenge: 16-octet PeerChallenge (IN)
75  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
76  * @username: 0-to-256-char UserName (IN)
77  * @username_len: Length of username
78  * @challenge: 8-octet Challenge (OUT)
79  * Returns: 0 on success, -1 on failure
80  */
81 int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82 		   const u8 *username, size_t username_len, u8 *challenge)
83 {
84 	u8 hash[SHA1_MAC_LEN];
85 	const unsigned char *addr[3];
86 	size_t len[3];
87 
88 	addr[0] = peer_challenge;
89 	len[0] = 16;
90 	addr[1] = auth_challenge;
91 	len[1] = 16;
92 	addr[2] = username;
93 	len[2] = username_len;
94 
95 	if (sha1_vector(3, addr, len, hash))
96 		return -1;
97 	os_memcpy(challenge, hash, 8);
98 	return 0;
99 }
100 
101 
102 /**
103  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
105  * @password_len: Length of password
106  * @password_hash: 16-octet PasswordHash (OUT)
107  * Returns: 0 on success, -1 on failure
108  */
109 int nt_password_hash(const u8 *password, size_t password_len,
110 		      u8 *password_hash)
111 {
112 	u8 buf[512], *pos;
113 	size_t len, max_len;
114 
115 	max_len = sizeof(buf);
116 	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117 		return -1;
118 
119 	len *= 2;
120 	pos = buf;
121 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
122 }
123 
124 
125 /**
126  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
127  * @password_hash: 16-octet PasswordHash (IN)
128  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
129  * Returns: 0 on success, -1 on failure
130  */
131 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
132 {
133 	size_t len = 16;
134 	return md4_vector(1, &password_hash, &len, password_hash_hash);
135 }
136 
137 
138 /**
139  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
140  * @challenge: 8-octet Challenge (IN)
141  * @password_hash: 16-octet PasswordHash (IN)
142  * @response: 24-octet Response (OUT)
143  * Returns: 0 on success, -1 on failure
144  */
145 int challenge_response(const u8 *challenge, const u8 *password_hash,
146 		       u8 *response)
147 {
148 	u8 zpwd[7];
149 
150 	if (des_encrypt(challenge, password_hash, response) < 0 ||
151 	    des_encrypt(challenge, password_hash + 7, response + 8) < 0)
152 		return -1;
153 	zpwd[0] = password_hash[14];
154 	zpwd[1] = password_hash[15];
155 	os_memset(zpwd + 2, 0, 5);
156 	return des_encrypt(challenge, zpwd, response + 16);
157 }
158 
159 
160 /**
161  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
162  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
163  * @peer_challenge: 16-octet PeerChallenge (IN)
164  * @username: 0-to-256-char UserName (IN)
165  * @username_len: Length of username
166  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
167  * @password_len: Length of password
168  * @response: 24-octet Response (OUT)
169  * Returns: 0 on success, -1 on failure
170  */
171 int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
172 			 const u8 *username, size_t username_len,
173 			 const u8 *password, size_t password_len,
174 			 u8 *response)
175 {
176 	u8 challenge[8];
177 	u8 password_hash[16];
178 
179 	if (challenge_hash(peer_challenge, auth_challenge, username,
180 			   username_len, challenge) ||
181 	    nt_password_hash(password, password_len, password_hash) ||
182 	    challenge_response(challenge, password_hash, response))
183 		return -1;
184 	return 0;
185 }
186 
187 
188 /**
189  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
190  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
191  * @peer_challenge: 16-octet PeerChallenge (IN)
192  * @username: 0-to-256-char UserName (IN)
193  * @username_len: Length of username
194  * @password_hash: 16-octet PasswordHash (IN)
195  * @response: 24-octet Response (OUT)
196  * Returns: 0 on success, -1 on failure
197  */
198 int generate_nt_response_pwhash(const u8 *auth_challenge,
199 				const u8 *peer_challenge,
200 				const u8 *username, size_t username_len,
201 				const u8 *password_hash,
202 				u8 *response)
203 {
204 	u8 challenge[8];
205 
206 	if (challenge_hash(peer_challenge, auth_challenge,
207 			   username, username_len,
208 			   challenge) ||
209 	    challenge_response(challenge, password_hash, response))
210 		return -1;
211 	return 0;
212 }
213 
214 
215 /**
216  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
217  * @password_hash: 16-octet PasswordHash (IN)
218  * @nt_response: 24-octet NT-Response (IN)
219  * @peer_challenge: 16-octet PeerChallenge (IN)
220  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
221  * @username: 0-to-256-char UserName (IN)
222  * @username_len: Length of username
223  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
224  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
225  * Returns: 0 on success, -1 on failure
226  */
227 int generate_authenticator_response_pwhash(
228 	const u8 *password_hash,
229 	const u8 *peer_challenge, const u8 *auth_challenge,
230 	const u8 *username, size_t username_len,
231 	const u8 *nt_response, u8 *response)
232 {
233 	static const u8 magic1[39] = {
234 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
235 		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
236 		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
237 		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
238 	};
239 	static const u8 magic2[41] = {
240 		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
241 		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
242 		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
243 		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
244 		0x6E
245 	};
246 
247 	u8 password_hash_hash[16], challenge[8];
248 	const unsigned char *addr1[3];
249 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
250 	const unsigned char *addr2[3];
251 	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
252 
253 	addr1[0] = password_hash_hash;
254 	addr1[1] = nt_response;
255 	addr1[2] = magic1;
256 
257 	addr2[0] = response;
258 	addr2[1] = challenge;
259 	addr2[2] = magic2;
260 
261 	if (hash_nt_password_hash(password_hash, password_hash_hash) ||
262 	    sha1_vector(3, addr1, len1, response) ||
263 	    challenge_hash(peer_challenge, auth_challenge, username,
264 			   username_len, challenge))
265 		return -1;
266 	return sha1_vector(3, addr2, len2, response);
267 }
268 
269 
270 /**
271  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
272  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
273  * @password_len: Length of password
274  * @nt_response: 24-octet NT-Response (IN)
275  * @peer_challenge: 16-octet PeerChallenge (IN)
276  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
277  * @username: 0-to-256-char UserName (IN)
278  * @username_len: Length of username
279  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
280  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
281  * Returns: 0 on success, -1 on failure
282  */
283 int generate_authenticator_response(const u8 *password, size_t password_len,
284 				    const u8 *peer_challenge,
285 				    const u8 *auth_challenge,
286 				    const u8 *username, size_t username_len,
287 				    const u8 *nt_response, u8 *response)
288 {
289 	u8 password_hash[16];
290 	if (nt_password_hash(password, password_len, password_hash))
291 		return -1;
292 	return generate_authenticator_response_pwhash(
293 		password_hash, peer_challenge, auth_challenge,
294 		username, username_len, nt_response, response);
295 }
296 
297 
298 /**
299  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
300  * @challenge: 8-octet Challenge (IN)
301  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
302  * @password_len: Length of password
303  * @response: 24-octet Response (OUT)
304  * Returns: 0 on success, -1 on failure
305  */
306 int nt_challenge_response(const u8 *challenge, const u8 *password,
307 			  size_t password_len, u8 *response)
308 {
309 	u8 password_hash[16];
310 
311 	if (nt_password_hash(password, password_len, password_hash) ||
312 	    challenge_response(challenge, password_hash, response))
313 		return -1;
314 	return 0;
315 }
316 
317 
318 /**
319  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
320  * @password_hash_hash: 16-octet PasswordHashHash (IN)
321  * @nt_response: 24-octet NTResponse (IN)
322  * @master_key: 16-octet MasterKey (OUT)
323  * Returns: 0 on success, -1 on failure
324  */
325 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
326 		   u8 *master_key)
327 {
328 	static const u8 magic1[27] = {
329 		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
330 		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
331 		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
332 	};
333 	const unsigned char *addr[3];
334 	const size_t len[3] = { 16, 24, sizeof(magic1) };
335 	u8 hash[SHA1_MAC_LEN];
336 
337 	addr[0] = password_hash_hash;
338 	addr[1] = nt_response;
339 	addr[2] = magic1;
340 
341 	if (sha1_vector(3, addr, len, hash))
342 		return -1;
343 	os_memcpy(master_key, hash, 16);
344 	return 0;
345 }
346 
347 
348 /**
349  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
350  * @master_key: 16-octet MasterKey (IN)
351  * @session_key: 8-to-16 octet SessionKey (OUT)
352  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
353  * @is_send: IsSend (IN, BOOLEAN)
354  * @is_server: IsServer (IN, BOOLEAN)
355  * Returns: 0 on success, -1 on failure
356  */
357 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
358 			    size_t session_key_len, int is_send,
359 			    int is_server)
360 {
361 	static const u8 magic2[84] = {
362 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
363 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
364 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365 		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
366 		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
367 		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
368 		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
369 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
370 		0x6b, 0x65, 0x79, 0x2e
371 	};
372 	static const u8 magic3[84] = {
373 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
374 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
375 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
376 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
377 		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
378 		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
379 		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
380 		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
381 		0x6b, 0x65, 0x79, 0x2e
382 	};
383 	static const u8 shs_pad1[40] = {
384 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
388 	};
389 
390 	static const u8 shs_pad2[40] = {
391 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
392 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
393 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
394 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
395 	};
396 	u8 digest[SHA1_MAC_LEN];
397 	const unsigned char *addr[4];
398 	const size_t len[4] = { 16, 40, 84, 40 };
399 
400 	addr[0] = master_key;
401 	addr[1] = shs_pad1;
402 	if (is_send) {
403 		addr[2] = is_server ? magic3 : magic2;
404 	} else {
405 		addr[2] = is_server ? magic2 : magic3;
406 	}
407 	addr[3] = shs_pad2;
408 
409 	if (sha1_vector(4, addr, len, digest))
410 		return -1;
411 
412 	if (session_key_len > SHA1_MAC_LEN)
413 		session_key_len = SHA1_MAC_LEN;
414 	os_memcpy(session_key, digest, session_key_len);
415 	return 0;
416 }
417 
418 
419 #ifndef CONFIG_NO_RC4
420 
421 #define PWBLOCK_LEN 516
422 
423 /**
424  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
425  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
426  * @password_len: Length of password
427  * @password_hash: 16-octet PasswordHash (IN)
428  * @pw_block: 516-byte PwBlock (OUT)
429  * Returns: 0 on success, -1 on failure
430  */
431 int encrypt_pw_block_with_password_hash(
432 	const u8 *password, size_t password_len,
433 	const u8 *password_hash, u8 *pw_block)
434 {
435 	size_t ucs2_len, offset;
436 	u8 *pos;
437 
438 	os_memset(pw_block, 0, PWBLOCK_LEN);
439 
440 	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
441 	    || ucs2_len > 256)
442 		return -1;
443 
444 	offset = (256 - ucs2_len) * 2;
445 	if (offset != 0) {
446 		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
447 		if (os_get_random(pw_block, offset) < 0)
448 			return -1;
449 	}
450 	/*
451 	 * PasswordLength is 4 octets, but since the maximum password length is
452 	 * 256, only first two (in little endian byte order) can be non-zero.
453 	 */
454 	pos = &pw_block[2 * 256];
455 	WPA_PUT_LE16(pos, password_len * 2);
456 	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
457 	return 0;
458 }
459 
460 
461 /**
462  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
463  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
464  * @new_password_len: Length of new_password
465  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
466  * @old_password_len: Length of old_password
467  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
468  * Returns: 0 on success, -1 on failure
469  */
470 int new_password_encrypted_with_old_nt_password_hash(
471 	const u8 *new_password, size_t new_password_len,
472 	const u8 *old_password, size_t old_password_len,
473 	u8 *encrypted_pw_block)
474 {
475 	u8 password_hash[16];
476 
477 	if (nt_password_hash(old_password, old_password_len, password_hash))
478 		return -1;
479 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
480 						password_hash,
481 						encrypted_pw_block))
482 		return -1;
483 	return 0;
484 }
485 
486 #endif /* CONFIG_NO_RC4 */
487 
488 
489 /**
490  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
491  * @password_hash: 16-octer PasswordHash (IN)
492  * @block: 16-octet Block (IN)
493  * @cypher: 16-octer Cypher (OUT)
494  * Returns: 0 on success, -1 on failure
495  */
496 int nt_password_hash_encrypted_with_block(const u8 *password_hash,
497 					  const u8 *block, u8 *cypher)
498 {
499 	if (des_encrypt(password_hash, block, cypher) < 0 ||
500 	    des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
501 		return -1;
502 	return 0;
503 }
504 
505 
506 /**
507  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
508  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
509  * @new_password_len: Length of new_password
510  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
511  * @old_password_len: Length of old_password
512  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
513  * Returns: 0 on success, -1 on failure
514  */
515 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
516 	const u8 *new_password, size_t new_password_len,
517 	const u8 *old_password, size_t old_password_len,
518 	u8 *encrypted_password_hash)
519 {
520 	u8 old_password_hash[16], new_password_hash[16];
521 
522 	if (nt_password_hash(old_password, old_password_len,
523 			     old_password_hash) ||
524 	    nt_password_hash(new_password, new_password_len,
525 			     new_password_hash) ||
526 	    nt_password_hash_encrypted_with_block(old_password_hash,
527 						  new_password_hash,
528 						  encrypted_password_hash))
529 		return -1;
530 	return 0;
531 }
532