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