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