xref: /freebsd/contrib/wpa/src/crypto/ms_funcs.c (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
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 ||
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  */
144 void challenge_response(const u8 *challenge, const u8 *password_hash,
145 			u8 *response)
146 {
147 	u8 zpwd[7];
148 	des_encrypt(challenge, password_hash, response);
149 	des_encrypt(challenge, password_hash + 7, response + 8);
150 	zpwd[0] = password_hash[14];
151 	zpwd[1] = password_hash[15];
152 	os_memset(zpwd + 2, 0, 5);
153 	des_encrypt(challenge, zpwd, response + 16);
154 }
155 
156 
157 /**
158  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
159  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
160  * @peer_challenge: 16-octet PeerChallenge (IN)
161  * @username: 0-to-256-char UserName (IN)
162  * @username_len: Length of username
163  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
164  * @password_len: Length of password
165  * @response: 24-octet Response (OUT)
166  * Returns: 0 on success, -1 on failure
167  */
168 int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
169 			 const u8 *username, size_t username_len,
170 			 const u8 *password, size_t password_len,
171 			 u8 *response)
172 {
173 	u8 challenge[8];
174 	u8 password_hash[16];
175 
176 	if (challenge_hash(peer_challenge, auth_challenge, username,
177 			   username_len, challenge) ||
178 	    nt_password_hash(password, password_len, password_hash))
179 		return -1;
180 	challenge_response(challenge, password_hash, response);
181 	return 0;
182 }
183 
184 
185 /**
186  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
187  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
188  * @peer_challenge: 16-octet PeerChallenge (IN)
189  * @username: 0-to-256-char UserName (IN)
190  * @username_len: Length of username
191  * @password_hash: 16-octet PasswordHash (IN)
192  * @response: 24-octet Response (OUT)
193  * Returns: 0 on success, -1 on failure
194  */
195 int generate_nt_response_pwhash(const u8 *auth_challenge,
196 				const u8 *peer_challenge,
197 				const u8 *username, size_t username_len,
198 				const u8 *password_hash,
199 				u8 *response)
200 {
201 	u8 challenge[8];
202 
203 	if (challenge_hash(peer_challenge, auth_challenge,
204 			   username, username_len,
205 			   challenge))
206 		return -1;
207 	challenge_response(challenge, password_hash, response);
208 	return 0;
209 }
210 
211 
212 /**
213  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
214  * @password_hash: 16-octet PasswordHash (IN)
215  * @nt_response: 24-octet NT-Response (IN)
216  * @peer_challenge: 16-octet PeerChallenge (IN)
217  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
218  * @username: 0-to-256-char UserName (IN)
219  * @username_len: Length of username
220  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
221  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
222  * Returns: 0 on success, -1 on failure
223  */
224 int generate_authenticator_response_pwhash(
225 	const u8 *password_hash,
226 	const u8 *peer_challenge, const u8 *auth_challenge,
227 	const u8 *username, size_t username_len,
228 	const u8 *nt_response, u8 *response)
229 {
230 	static const u8 magic1[39] = {
231 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
232 		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
233 		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
234 		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
235 	};
236 	static const u8 magic2[41] = {
237 		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
238 		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
239 		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
240 		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
241 		0x6E
242 	};
243 
244 	u8 password_hash_hash[16], challenge[8];
245 	const unsigned char *addr1[3];
246 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
247 	const unsigned char *addr2[3];
248 	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
249 
250 	addr1[0] = password_hash_hash;
251 	addr1[1] = nt_response;
252 	addr1[2] = magic1;
253 
254 	addr2[0] = response;
255 	addr2[1] = challenge;
256 	addr2[2] = magic2;
257 
258 	if (hash_nt_password_hash(password_hash, password_hash_hash) ||
259 	    sha1_vector(3, addr1, len1, response) ||
260 	    challenge_hash(peer_challenge, auth_challenge, username,
261 			   username_len, challenge))
262 		return -1;
263 	return sha1_vector(3, addr2, len2, response);
264 }
265 
266 
267 /**
268  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
269  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
270  * @password_len: Length of password
271  * @nt_response: 24-octet NT-Response (IN)
272  * @peer_challenge: 16-octet PeerChallenge (IN)
273  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
274  * @username: 0-to-256-char UserName (IN)
275  * @username_len: Length of username
276  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
277  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
278  * Returns: 0 on success, -1 on failure
279  */
280 int generate_authenticator_response(const u8 *password, size_t password_len,
281 				    const u8 *peer_challenge,
282 				    const u8 *auth_challenge,
283 				    const u8 *username, size_t username_len,
284 				    const u8 *nt_response, u8 *response)
285 {
286 	u8 password_hash[16];
287 	if (nt_password_hash(password, password_len, password_hash))
288 		return -1;
289 	return generate_authenticator_response_pwhash(
290 		password_hash, peer_challenge, auth_challenge,
291 		username, username_len, nt_response, response);
292 }
293 
294 
295 /**
296  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
297  * @challenge: 8-octet Challenge (IN)
298  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
299  * @password_len: Length of password
300  * @response: 24-octet Response (OUT)
301  * Returns: 0 on success, -1 on failure
302  */
303 int nt_challenge_response(const u8 *challenge, const u8 *password,
304 			  size_t password_len, u8 *response)
305 {
306 	u8 password_hash[16];
307 	if (nt_password_hash(password, password_len, password_hash))
308 		return -1;
309 	challenge_response(challenge, password_hash, response);
310 	return 0;
311 }
312 
313 
314 /**
315  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
316  * @password_hash_hash: 16-octet PasswordHashHash (IN)
317  * @nt_response: 24-octet NTResponse (IN)
318  * @master_key: 16-octet MasterKey (OUT)
319  * Returns: 0 on success, -1 on failure
320  */
321 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
322 		   u8 *master_key)
323 {
324 	static const u8 magic1[27] = {
325 		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
326 		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
327 		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
328 	};
329 	const unsigned char *addr[3];
330 	const size_t len[3] = { 16, 24, sizeof(magic1) };
331 	u8 hash[SHA1_MAC_LEN];
332 
333 	addr[0] = password_hash_hash;
334 	addr[1] = nt_response;
335 	addr[2] = magic1;
336 
337 	if (sha1_vector(3, addr, len, hash))
338 		return -1;
339 	os_memcpy(master_key, hash, 16);
340 	return 0;
341 }
342 
343 
344 /**
345  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
346  * @master_key: 16-octet MasterKey (IN)
347  * @session_key: 8-to-16 octet SessionKey (OUT)
348  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
349  * @is_send: IsSend (IN, BOOLEAN)
350  * @is_server: IsServer (IN, BOOLEAN)
351  * Returns: 0 on success, -1 on failure
352  */
353 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
354 			    size_t session_key_len, int is_send,
355 			    int is_server)
356 {
357 	static const u8 magic2[84] = {
358 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
359 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
360 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
361 		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
362 		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
363 		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
364 		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
366 		0x6b, 0x65, 0x79, 0x2e
367 	};
368 	static const u8 magic3[84] = {
369 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
370 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
371 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
372 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
373 		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
374 		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
375 		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
376 		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
377 		0x6b, 0x65, 0x79, 0x2e
378 	};
379 	static const u8 shs_pad1[40] = {
380 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
384 	};
385 
386 	static const u8 shs_pad2[40] = {
387 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
388 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
389 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
391 	};
392 	u8 digest[SHA1_MAC_LEN];
393 	const unsigned char *addr[4];
394 	const size_t len[4] = { 16, 40, 84, 40 };
395 
396 	addr[0] = master_key;
397 	addr[1] = shs_pad1;
398 	if (is_send) {
399 		addr[2] = is_server ? magic3 : magic2;
400 	} else {
401 		addr[2] = is_server ? magic2 : magic3;
402 	}
403 	addr[3] = shs_pad2;
404 
405 	if (sha1_vector(4, addr, len, digest))
406 		return -1;
407 
408 	if (session_key_len > SHA1_MAC_LEN)
409 		session_key_len = SHA1_MAC_LEN;
410 	os_memcpy(session_key, digest, session_key_len);
411 	return 0;
412 }
413 
414 
415 #ifndef CONFIG_NO_RC4
416 
417 #define PWBLOCK_LEN 516
418 
419 /**
420  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
421  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
422  * @password_len: Length of password
423  * @password_hash: 16-octet PasswordHash (IN)
424  * @pw_block: 516-byte PwBlock (OUT)
425  * Returns: 0 on success, -1 on failure
426  */
427 int encrypt_pw_block_with_password_hash(
428 	const u8 *password, size_t password_len,
429 	const u8 *password_hash, u8 *pw_block)
430 {
431 	size_t ucs2_len, offset;
432 	u8 *pos;
433 
434 	os_memset(pw_block, 0, PWBLOCK_LEN);
435 
436 	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
437 	    || ucs2_len > 256)
438 		return -1;
439 
440 	offset = (256 - ucs2_len) * 2;
441 	if (offset != 0) {
442 		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
443 		if (os_get_random(pw_block, offset) < 0)
444 			return -1;
445 	}
446 	/*
447 	 * PasswordLength is 4 octets, but since the maximum password length is
448 	 * 256, only first two (in little endian byte order) can be non-zero.
449 	 */
450 	pos = &pw_block[2 * 256];
451 	WPA_PUT_LE16(pos, password_len * 2);
452 	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
453 	return 0;
454 }
455 
456 
457 /**
458  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
459  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
460  * @new_password_len: Length of new_password
461  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
462  * @old_password_len: Length of old_password
463  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
464  * Returns: 0 on success, -1 on failure
465  */
466 int new_password_encrypted_with_old_nt_password_hash(
467 	const u8 *new_password, size_t new_password_len,
468 	const u8 *old_password, size_t old_password_len,
469 	u8 *encrypted_pw_block)
470 {
471 	u8 password_hash[16];
472 
473 	if (nt_password_hash(old_password, old_password_len, password_hash))
474 		return -1;
475 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
476 						password_hash,
477 						encrypted_pw_block))
478 		return -1;
479 	return 0;
480 }
481 
482 #endif /* CONFIG_NO_RC4 */
483 
484 
485 /**
486  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
487  * @password_hash: 16-octer PasswordHash (IN)
488  * @block: 16-octet Block (IN)
489  * @cypher: 16-octer Cypher (OUT)
490  */
491 void nt_password_hash_encrypted_with_block(const u8 *password_hash,
492 					   const u8 *block, u8 *cypher)
493 {
494 	des_encrypt(password_hash, block, cypher);
495 	des_encrypt(password_hash + 8, block + 7, cypher + 8);
496 }
497 
498 
499 /**
500  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
501  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
502  * @new_password_len: Length of new_password
503  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
504  * @old_password_len: Length of old_password
505  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
506  * Returns: 0 on success, -1 on failure
507  */
508 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
509 	const u8 *new_password, size_t new_password_len,
510 	const u8 *old_password, size_t old_password_len,
511 	u8 *encrypted_password_hash)
512 {
513 	u8 old_password_hash[16], new_password_hash[16];
514 
515 	if (nt_password_hash(old_password, old_password_len,
516 			     old_password_hash) ||
517 	    nt_password_hash(new_password, new_password_len,
518 			     new_password_hash))
519 		return -1;
520 	nt_password_hash_encrypted_with_block(old_password_hash,
521 					      new_password_hash,
522 					      encrypted_password_hash);
523 	return 0;
524 }
525