ms_funcs.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
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 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			}
62		}
63	}
64
65	if (ucs2_string_size)
66		*ucs2_string_size = j / 2;
67	return 0;
68}
69
70
71/**
72 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
73 * @peer_challenge: 16-octet PeerChallenge (IN)
74 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
75 * @username: 0-to-256-char UserName (IN)
76 * @username_len: Length of username
77 * @challenge: 8-octet Challenge (OUT)
78 * Returns: 0 on success, -1 on failure
79 */
80static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
81			  const u8 *username, size_t username_len,
82			  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 */
144void 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 */
168int 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	challenge_hash(peer_challenge, auth_challenge, username, username_len,
177		       challenge);
178	if (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 */
195int 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 */
224int 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		return -1;
260	if (sha1_vector(3, addr1, len1, response))
261		return -1;
262
263	challenge_hash(peer_challenge, auth_challenge, username, username_len,
264		       challenge);
265	return sha1_vector(3, addr2, len2, response);
266}
267
268
269/**
270 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
271 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
272 * @password_len: Length of password
273 * @nt_response: 24-octet NT-Response (IN)
274 * @peer_challenge: 16-octet PeerChallenge (IN)
275 * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
276 * @username: 0-to-256-char UserName (IN)
277 * @username_len: Length of username
278 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
279 * encoded as a 42-octet ASCII string (S=hexdump_of_response)
280 * Returns: 0 on success, -1 on failure
281 */
282int generate_authenticator_response(const u8 *password, size_t password_len,
283				    const u8 *peer_challenge,
284				    const u8 *auth_challenge,
285				    const u8 *username, size_t username_len,
286				    const u8 *nt_response, u8 *response)
287{
288	u8 password_hash[16];
289	if (nt_password_hash(password, password_len, password_hash))
290		return -1;
291	return generate_authenticator_response_pwhash(
292		password_hash, peer_challenge, auth_challenge,
293		username, username_len, nt_response, response);
294}
295
296
297/**
298 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
299 * @challenge: 8-octet Challenge (IN)
300 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
301 * @password_len: Length of password
302 * @response: 24-octet Response (OUT)
303 * Returns: 0 on success, -1 on failure
304 */
305int nt_challenge_response(const u8 *challenge, const u8 *password,
306			  size_t password_len, u8 *response)
307{
308	u8 password_hash[16];
309	if (nt_password_hash(password, password_len, password_hash))
310		return -1;
311	challenge_response(challenge, password_hash, response);
312	return 0;
313}
314
315
316/**
317 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
318 * @password_hash_hash: 16-octet PasswordHashHash (IN)
319 * @nt_response: 24-octet NTResponse (IN)
320 * @master_key: 16-octet MasterKey (OUT)
321 * Returns: 0 on success, -1 on failure
322 */
323int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
324		   u8 *master_key)
325{
326	static const u8 magic1[27] = {
327		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
328		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
329		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
330	};
331	const unsigned char *addr[3];
332	const size_t len[3] = { 16, 24, sizeof(magic1) };
333	u8 hash[SHA1_MAC_LEN];
334
335	addr[0] = password_hash_hash;
336	addr[1] = nt_response;
337	addr[2] = magic1;
338
339	if (sha1_vector(3, addr, len, hash))
340		return -1;
341	os_memcpy(master_key, hash, 16);
342	return 0;
343}
344
345
346/**
347 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
348 * @master_key: 16-octet MasterKey (IN)
349 * @session_key: 8-to-16 octet SessionKey (OUT)
350 * @session_key_len: SessionKeyLength (Length of session_key) (IN)
351 * @is_send: IsSend (IN, BOOLEAN)
352 * @is_server: IsServer (IN, BOOLEAN)
353 * Returns: 0 on success, -1 on failure
354 */
355int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
356			    size_t session_key_len, int is_send,
357			    int is_server)
358{
359	static const u8 magic2[84] = {
360		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
361		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
362		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
363		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
364		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
365		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
366		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
367		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
368		0x6b, 0x65, 0x79, 0x2e
369	};
370	static const u8 magic3[84] = {
371		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
372		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
373		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
374		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
375		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
376		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
377		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
378		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
379		0x6b, 0x65, 0x79, 0x2e
380	};
381	static const u8 shs_pad1[40] = {
382		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
386	};
387
388	static const u8 shs_pad2[40] = {
389		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
391		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
392		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
393	};
394	u8 digest[SHA1_MAC_LEN];
395	const unsigned char *addr[4];
396	const size_t len[4] = { 16, 40, 84, 40 };
397
398	addr[0] = master_key;
399	addr[1] = shs_pad1;
400	if (is_send) {
401		addr[2] = is_server ? magic3 : magic2;
402	} else {
403		addr[2] = is_server ? magic2 : magic3;
404	}
405	addr[3] = shs_pad2;
406
407	if (sha1_vector(4, addr, len, digest))
408		return -1;
409
410	if (session_key_len > SHA1_MAC_LEN)
411		session_key_len = SHA1_MAC_LEN;
412	os_memcpy(session_key, digest, session_key_len);
413	return 0;
414}
415
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 */
427int 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		return -1;
438
439	if (ucs2_len > 256)
440		return -1;
441
442	offset = (256 - ucs2_len) * 2;
443	if (offset != 0) {
444		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
445		if (os_get_random(pw_block, offset) < 0)
446			return -1;
447	}
448	/*
449	 * PasswordLength is 4 octets, but since the maximum password length is
450	 * 256, only first two (in little endian byte order) can be non-zero.
451	 */
452	pos = &pw_block[2 * 256];
453	WPA_PUT_LE16(pos, password_len * 2);
454	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
455	return 0;
456}
457
458
459/**
460 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
461 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
462 * @new_password_len: Length of new_password
463 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
464 * @old_password_len: Length of old_password
465 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
466 * Returns: 0 on success, -1 on failure
467 */
468int new_password_encrypted_with_old_nt_password_hash(
469	const u8 *new_password, size_t new_password_len,
470	const u8 *old_password, size_t old_password_len,
471	u8 *encrypted_pw_block)
472{
473	u8 password_hash[16];
474
475	if (nt_password_hash(old_password, old_password_len, password_hash))
476		return -1;
477	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
478						password_hash,
479						encrypted_pw_block))
480		return -1;
481	return 0;
482}
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 */
491void 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 */
508int 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