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 */
25static 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 */
81int 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 */
109int 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 */
131int 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 */
145int 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 */
171int 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 */
198int 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 */
227int 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 */
283int 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 */
306int 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 */
325int 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 */
357int 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 */
431int 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 */
470int 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 */
496int 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 */
515int 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