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