• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2006, 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  */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)32 static 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  */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)58 void 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 		return;
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  */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)84 void 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  */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)97 void 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_hallenge: 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  */
generate_nt_response(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password,size_t password_len,u8 * response)120 void 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_hallenge: 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  */
generate_nt_response_pwhash(const u8 * auth_challenge,const u8 * peer_challenge,const u8 * username,size_t username_len,const u8 * password_hash,u8 * response)144 void 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  */
generate_authenticator_response_pwhash(const u8 * password_hash,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)169 void 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  */
generate_authenticator_response(const u8 * password,size_t password_len,const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,const u8 * nt_response,u8 * response)224 void 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  */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)246 void 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  */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)261 void 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  */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)290 void 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  */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)359 static void encrypt_pw_block_with_password_hash(
360 	const u8 *password, size_t password_len,
361 	const u8 *password_hash, u8 *pw_block)
362 {
363 	size_t i, offset;
364 	u8 *pos;
365 
366 	if (password_len > 256)
367 		return;
368 
369 	os_memset(pw_block, 0, PWBLOCK_LEN);
370 	offset = (256 - password_len) * 2;
371 	os_get_random(pw_block, offset);
372 	for (i = 0; i < password_len; i++)
373 		pw_block[offset + i * 2] = password[i];
374 	/*
375 	 * PasswordLength is 4 octets, but since the maximum password length is
376 	 * 256, only first two (in little endian byte order) can be non-zero.
377 	 */
378 	pos = &pw_block[2 * 256];
379 	WPA_PUT_LE16(pos, password_len * 2);
380 	rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
381 }
382 
383 
384 /**
385  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
386  * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
387  * @new_password_len: Length of new_password
388  * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
389  * @old_password_len: Length of old_password
390  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
391  */
new_password_encrypted_with_old_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_pw_block)392 void new_password_encrypted_with_old_nt_password_hash(
393 	const u8 *new_password, size_t new_password_len,
394 	const u8 *old_password, size_t old_password_len,
395 	u8 *encrypted_pw_block)
396 {
397 	u8 password_hash[16];
398 
399 	nt_password_hash(old_password, old_password_len, password_hash);
400 	encrypt_pw_block_with_password_hash(new_password, new_password_len,
401 					    password_hash, encrypted_pw_block);
402 }
403 
404 
405 /**
406  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
407  * @password_hash: 16-octer PasswordHash (IN)
408  * @block: 16-octet Block (IN)
409  * @cypher: 16-octer Cypher (OUT)
410  */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)411 static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
412 						  const u8 *block,
413 						  u8 *cypher)
414 {
415 	des_encrypt(password_hash, block, cypher);
416 	des_encrypt(password_hash + 8, block + 7, cypher + 8);
417 }
418 
419 
420 /**
421  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
422  * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
423  * @new_password_len: Length of new_password
424  * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
425  * @old_password_len: Length of old_password
426  * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
427  */
old_nt_password_hash_encrypted_with_new_nt_password_hash(const u8 * new_password,size_t new_password_len,const u8 * old_password,size_t old_password_len,u8 * encrypted_password_hash)428 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
429 	const u8 *new_password, size_t new_password_len,
430 	const u8 *old_password, size_t old_password_len,
431 	u8 *encrypted_password_hash)
432 {
433 	u8 old_password_hash[16], new_password_hash[16];
434 
435 	nt_password_hash(old_password, old_password_len, old_password_hash);
436 	nt_password_hash(new_password, new_password_len, new_password_hash);
437 	nt_password_hash_encrypted_with_block(old_password_hash,
438 					      new_password_hash,
439 					      encrypted_password_hash);
440 }
441