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