ms_funcs.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
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 */
31static 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 */
86static 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 */
115int 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 */
137int 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 */
150void 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 */
174int 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 */
201int 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 */
230int 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 */
288int 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 */
311int 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 */
329int 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 */
361int 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 */
433int 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 */
474int 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 */
497void 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 */
514int 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