xref: /freebsd/contrib/wpa/src/crypto/ms_funcs.c (revision 67350cb56a69468c118bd4ccf6e361b7ebfa9eb4)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3f05cddf9SRui Paulo  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
1239beb93cSSam Leffler #include "sha1.h"
1339beb93cSSam Leffler #include "ms_funcs.h"
1439beb93cSSam Leffler #include "crypto.h"
1539beb93cSSam Leffler 
16f05cddf9SRui Paulo /**
17f05cddf9SRui Paulo  * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18f05cddf9SRui Paulo  * @utf8_string: UTF-8 string (IN)
19f05cddf9SRui Paulo  * @utf8_string_len: Length of utf8_string (IN)
20f05cddf9SRui Paulo  * @ucs2_buffer: UCS-2 buffer (OUT)
21f05cddf9SRui Paulo  * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
22f05cddf9SRui Paulo  * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
23f05cddf9SRui Paulo  * Returns: 0 on success, -1 on failure
24f05cddf9SRui Paulo  */
utf8_to_ucs2(const u8 * utf8_string,size_t utf8_string_len,u8 * ucs2_buffer,size_t ucs2_buffer_size,size_t * ucs2_string_size)25f05cddf9SRui Paulo static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
26f05cddf9SRui Paulo                         u8 *ucs2_buffer, size_t ucs2_buffer_size,
27f05cddf9SRui Paulo                         size_t *ucs2_string_size)
28f05cddf9SRui Paulo {
29f05cddf9SRui Paulo 	size_t i, j;
30f05cddf9SRui Paulo 
31f05cddf9SRui Paulo 	for (i = 0, j = 0; i < utf8_string_len; i++) {
32f05cddf9SRui Paulo 		u8 c = utf8_string[i];
33f05cddf9SRui Paulo 		if (j >= ucs2_buffer_size) {
34f05cddf9SRui Paulo 			/* input too long */
35f05cddf9SRui Paulo 			return -1;
36f05cddf9SRui Paulo 		}
37f05cddf9SRui Paulo 		if (c <= 0x7F) {
38f05cddf9SRui Paulo 			WPA_PUT_LE16(ucs2_buffer + j, c);
39f05cddf9SRui Paulo 			j += 2;
40f05cddf9SRui Paulo 		} else if (i == utf8_string_len - 1 ||
41f05cddf9SRui Paulo 			   j >= ucs2_buffer_size - 1) {
42f05cddf9SRui Paulo 			/* incomplete surrogate */
43f05cddf9SRui Paulo 			return -1;
44f05cddf9SRui Paulo 		} else {
45f05cddf9SRui Paulo 			u8 c2 = utf8_string[++i];
46f05cddf9SRui Paulo 			if ((c & 0xE0) == 0xC0) {
47f05cddf9SRui Paulo 				/* two-byte encoding */
48f05cddf9SRui Paulo 				WPA_PUT_LE16(ucs2_buffer + j,
49f05cddf9SRui Paulo 					     ((c & 0x1F) << 6) | (c2 & 0x3F));
50f05cddf9SRui Paulo 				j += 2;
51780fb4a2SCy Schubert 			} else if (i == utf8_string_len - 1 ||
52f05cddf9SRui Paulo 				   j >= ucs2_buffer_size - 1) {
53f05cddf9SRui Paulo 				/* incomplete surrogate */
54f05cddf9SRui Paulo 				return -1;
55f05cddf9SRui Paulo 			} else {
56f05cddf9SRui Paulo 				/* three-byte encoding */
57f05cddf9SRui Paulo 				u8 c3 = utf8_string[++i];
58f05cddf9SRui Paulo 				WPA_PUT_LE16(ucs2_buffer + j,
59f05cddf9SRui Paulo 					     ((c & 0xF) << 12) |
60f05cddf9SRui Paulo 					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
615b9c547cSRui Paulo 				j += 2;
62f05cddf9SRui Paulo 			}
63f05cddf9SRui Paulo 		}
64f05cddf9SRui Paulo 	}
65f05cddf9SRui Paulo 
66f05cddf9SRui Paulo 	if (ucs2_string_size)
67f05cddf9SRui Paulo 		*ucs2_string_size = j / 2;
68f05cddf9SRui Paulo 	return 0;
69f05cddf9SRui Paulo }
70f05cddf9SRui Paulo 
7139beb93cSSam Leffler 
7239beb93cSSam Leffler /**
7339beb93cSSam Leffler  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
7439beb93cSSam Leffler  * @peer_challenge: 16-octet PeerChallenge (IN)
7539beb93cSSam Leffler  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
7639beb93cSSam Leffler  * @username: 0-to-256-char UserName (IN)
7739beb93cSSam Leffler  * @username_len: Length of username
7839beb93cSSam Leffler  * @challenge: 8-octet Challenge (OUT)
79e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
8039beb93cSSam Leffler  */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)81325151a3SRui Paulo int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82325151a3SRui Paulo 		   const u8 *username, size_t username_len, u8 *challenge)
8339beb93cSSam Leffler {
8439beb93cSSam Leffler 	u8 hash[SHA1_MAC_LEN];
8539beb93cSSam Leffler 	const unsigned char *addr[3];
8639beb93cSSam Leffler 	size_t len[3];
8739beb93cSSam Leffler 
8839beb93cSSam Leffler 	addr[0] = peer_challenge;
8939beb93cSSam Leffler 	len[0] = 16;
9039beb93cSSam Leffler 	addr[1] = auth_challenge;
9139beb93cSSam Leffler 	len[1] = 16;
9239beb93cSSam Leffler 	addr[2] = username;
9339beb93cSSam Leffler 	len[2] = username_len;
9439beb93cSSam Leffler 
95e28a4053SRui Paulo 	if (sha1_vector(3, addr, len, hash))
96e28a4053SRui Paulo 		return -1;
9739beb93cSSam Leffler 	os_memcpy(challenge, hash, 8);
98e28a4053SRui Paulo 	return 0;
9939beb93cSSam Leffler }
10039beb93cSSam Leffler 
10139beb93cSSam Leffler 
10239beb93cSSam Leffler /**
10339beb93cSSam Leffler  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104f05cddf9SRui Paulo  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
10539beb93cSSam Leffler  * @password_len: Length of password
10639beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (OUT)
107e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
10839beb93cSSam Leffler  */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)109e28a4053SRui Paulo int nt_password_hash(const u8 *password, size_t password_len,
11039beb93cSSam Leffler 		      u8 *password_hash)
11139beb93cSSam Leffler {
11239beb93cSSam Leffler 	u8 buf[512], *pos;
113f05cddf9SRui Paulo 	size_t len, max_len;
11439beb93cSSam Leffler 
115f05cddf9SRui Paulo 	max_len = sizeof(buf);
116f05cddf9SRui Paulo 	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117f05cddf9SRui Paulo 		return -1;
11839beb93cSSam Leffler 
119f05cddf9SRui Paulo 	len *= 2;
12039beb93cSSam Leffler 	pos = buf;
121e28a4053SRui Paulo 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
12239beb93cSSam Leffler }
12339beb93cSSam Leffler 
12439beb93cSSam Leffler 
12539beb93cSSam Leffler /**
12639beb93cSSam Leffler  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
12739beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (IN)
12839beb93cSSam Leffler  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
129e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
13039beb93cSSam Leffler  */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)131e28a4053SRui Paulo int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
13239beb93cSSam Leffler {
13339beb93cSSam Leffler 	size_t len = 16;
134e28a4053SRui Paulo 	return md4_vector(1, &password_hash, &len, password_hash_hash);
13539beb93cSSam Leffler }
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 
13839beb93cSSam Leffler /**
13939beb93cSSam Leffler  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
14039beb93cSSam Leffler  * @challenge: 8-octet Challenge (IN)
14139beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (IN)
14239beb93cSSam Leffler  * @response: 24-octet Response (OUT)
143*85732ac8SCy Schubert  * Returns: 0 on success, -1 on failure
14439beb93cSSam Leffler  */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)145*85732ac8SCy Schubert int challenge_response(const u8 *challenge, const u8 *password_hash,
14639beb93cSSam Leffler 		       u8 *response)
14739beb93cSSam Leffler {
14839beb93cSSam Leffler 	u8 zpwd[7];
149*85732ac8SCy Schubert 
150*85732ac8SCy Schubert 	if (des_encrypt(challenge, password_hash, response) < 0 ||
151*85732ac8SCy Schubert 	    des_encrypt(challenge, password_hash + 7, response + 8) < 0)
152*85732ac8SCy Schubert 		return -1;
15339beb93cSSam Leffler 	zpwd[0] = password_hash[14];
15439beb93cSSam Leffler 	zpwd[1] = password_hash[15];
15539beb93cSSam Leffler 	os_memset(zpwd + 2, 0, 5);
156*85732ac8SCy Schubert 	return des_encrypt(challenge, zpwd, response + 16);
15739beb93cSSam Leffler }
15839beb93cSSam Leffler 
15939beb93cSSam Leffler 
16039beb93cSSam Leffler /**
16139beb93cSSam Leffler  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
16239beb93cSSam Leffler  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
16339beb93cSSam Leffler  * @peer_challenge: 16-octet PeerChallenge (IN)
16439beb93cSSam Leffler  * @username: 0-to-256-char UserName (IN)
16539beb93cSSam Leffler  * @username_len: Length of username
166f05cddf9SRui Paulo  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
16739beb93cSSam Leffler  * @password_len: Length of password
16839beb93cSSam Leffler  * @response: 24-octet Response (OUT)
169e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
17039beb93cSSam Leffler  */
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)171e28a4053SRui Paulo int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
17239beb93cSSam Leffler 			 const u8 *username, size_t username_len,
17339beb93cSSam Leffler 			 const u8 *password, size_t password_len,
17439beb93cSSam Leffler 			 u8 *response)
17539beb93cSSam Leffler {
17639beb93cSSam Leffler 	u8 challenge[8];
17739beb93cSSam Leffler 	u8 password_hash[16];
17839beb93cSSam Leffler 
179f05cddf9SRui Paulo 	if (challenge_hash(peer_challenge, auth_challenge, username,
180325151a3SRui Paulo 			   username_len, challenge) ||
181*85732ac8SCy Schubert 	    nt_password_hash(password, password_len, password_hash) ||
182*85732ac8SCy Schubert 	    challenge_response(challenge, password_hash, response))
183e28a4053SRui Paulo 		return -1;
184e28a4053SRui Paulo 	return 0;
18539beb93cSSam Leffler }
18639beb93cSSam Leffler 
18739beb93cSSam Leffler 
18839beb93cSSam Leffler /**
18939beb93cSSam Leffler  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
19039beb93cSSam Leffler  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
19139beb93cSSam Leffler  * @peer_challenge: 16-octet PeerChallenge (IN)
19239beb93cSSam Leffler  * @username: 0-to-256-char UserName (IN)
19339beb93cSSam Leffler  * @username_len: Length of username
19439beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (IN)
19539beb93cSSam Leffler  * @response: 24-octet Response (OUT)
196e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
19739beb93cSSam Leffler  */
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)198e28a4053SRui Paulo int generate_nt_response_pwhash(const u8 *auth_challenge,
19939beb93cSSam Leffler 				const u8 *peer_challenge,
20039beb93cSSam Leffler 				const u8 *username, size_t username_len,
20139beb93cSSam Leffler 				const u8 *password_hash,
20239beb93cSSam Leffler 				u8 *response)
20339beb93cSSam Leffler {
20439beb93cSSam Leffler 	u8 challenge[8];
20539beb93cSSam Leffler 
206e28a4053SRui Paulo 	if (challenge_hash(peer_challenge, auth_challenge,
207e28a4053SRui Paulo 			   username, username_len,
208*85732ac8SCy Schubert 			   challenge) ||
209*85732ac8SCy Schubert 	    challenge_response(challenge, password_hash, response))
210e28a4053SRui Paulo 		return -1;
211e28a4053SRui Paulo 	return 0;
21239beb93cSSam Leffler }
21339beb93cSSam Leffler 
21439beb93cSSam Leffler 
21539beb93cSSam Leffler /**
21639beb93cSSam Leffler  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
21739beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (IN)
21839beb93cSSam Leffler  * @nt_response: 24-octet NT-Response (IN)
21939beb93cSSam Leffler  * @peer_challenge: 16-octet PeerChallenge (IN)
22039beb93cSSam Leffler  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
22139beb93cSSam Leffler  * @username: 0-to-256-char UserName (IN)
22239beb93cSSam Leffler  * @username_len: Length of username
22339beb93cSSam Leffler  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
22439beb93cSSam Leffler  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
225e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
22639beb93cSSam Leffler  */
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)227e28a4053SRui Paulo int generate_authenticator_response_pwhash(
22839beb93cSSam Leffler 	const u8 *password_hash,
22939beb93cSSam Leffler 	const u8 *peer_challenge, const u8 *auth_challenge,
23039beb93cSSam Leffler 	const u8 *username, size_t username_len,
23139beb93cSSam Leffler 	const u8 *nt_response, u8 *response)
23239beb93cSSam Leffler {
23339beb93cSSam Leffler 	static const u8 magic1[39] = {
23439beb93cSSam Leffler 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
23539beb93cSSam Leffler 		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
23639beb93cSSam Leffler 		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
23739beb93cSSam Leffler 		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
23839beb93cSSam Leffler 	};
23939beb93cSSam Leffler 	static const u8 magic2[41] = {
24039beb93cSSam Leffler 		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
24139beb93cSSam Leffler 		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
24239beb93cSSam Leffler 		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
24339beb93cSSam Leffler 		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
24439beb93cSSam Leffler 		0x6E
24539beb93cSSam Leffler 	};
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 	u8 password_hash_hash[16], challenge[8];
24839beb93cSSam Leffler 	const unsigned char *addr1[3];
24939beb93cSSam Leffler 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
25039beb93cSSam Leffler 	const unsigned char *addr2[3];
25139beb93cSSam Leffler 	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 	addr1[0] = password_hash_hash;
25439beb93cSSam Leffler 	addr1[1] = nt_response;
25539beb93cSSam Leffler 	addr1[2] = magic1;
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 	addr2[0] = response;
25839beb93cSSam Leffler 	addr2[1] = challenge;
25939beb93cSSam Leffler 	addr2[2] = magic2;
26039beb93cSSam Leffler 
261325151a3SRui Paulo 	if (hash_nt_password_hash(password_hash, password_hash_hash) ||
262325151a3SRui Paulo 	    sha1_vector(3, addr1, len1, response) ||
263325151a3SRui Paulo 	    challenge_hash(peer_challenge, auth_challenge, username,
264f05cddf9SRui Paulo 			   username_len, challenge))
265f05cddf9SRui Paulo 		return -1;
266e28a4053SRui Paulo 	return sha1_vector(3, addr2, len2, response);
26739beb93cSSam Leffler }
26839beb93cSSam Leffler 
26939beb93cSSam Leffler 
27039beb93cSSam Leffler /**
27139beb93cSSam Leffler  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
272f05cddf9SRui Paulo  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
27339beb93cSSam Leffler  * @password_len: Length of password
27439beb93cSSam Leffler  * @nt_response: 24-octet NT-Response (IN)
27539beb93cSSam Leffler  * @peer_challenge: 16-octet PeerChallenge (IN)
27639beb93cSSam Leffler  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
27739beb93cSSam Leffler  * @username: 0-to-256-char UserName (IN)
27839beb93cSSam Leffler  * @username_len: Length of username
27939beb93cSSam Leffler  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
28039beb93cSSam Leffler  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
281e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
28239beb93cSSam Leffler  */
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)283e28a4053SRui Paulo int generate_authenticator_response(const u8 *password, size_t password_len,
28439beb93cSSam Leffler 				    const u8 *peer_challenge,
28539beb93cSSam Leffler 				    const u8 *auth_challenge,
28639beb93cSSam Leffler 				    const u8 *username, size_t username_len,
28739beb93cSSam Leffler 				    const u8 *nt_response, u8 *response)
28839beb93cSSam Leffler {
28939beb93cSSam Leffler 	u8 password_hash[16];
290e28a4053SRui Paulo 	if (nt_password_hash(password, password_len, password_hash))
291e28a4053SRui Paulo 		return -1;
292e28a4053SRui Paulo 	return generate_authenticator_response_pwhash(
293e28a4053SRui Paulo 		password_hash, peer_challenge, auth_challenge,
294e28a4053SRui Paulo 		username, username_len, nt_response, response);
29539beb93cSSam Leffler }
29639beb93cSSam Leffler 
29739beb93cSSam Leffler 
29839beb93cSSam Leffler /**
29939beb93cSSam Leffler  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
30039beb93cSSam Leffler  * @challenge: 8-octet Challenge (IN)
301f05cddf9SRui Paulo  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
30239beb93cSSam Leffler  * @password_len: Length of password
30339beb93cSSam Leffler  * @response: 24-octet Response (OUT)
304e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
30539beb93cSSam Leffler  */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)306e28a4053SRui Paulo int nt_challenge_response(const u8 *challenge, const u8 *password,
30739beb93cSSam Leffler 			  size_t password_len, u8 *response)
30839beb93cSSam Leffler {
30939beb93cSSam Leffler 	u8 password_hash[16];
310*85732ac8SCy Schubert 
311*85732ac8SCy Schubert 	if (nt_password_hash(password, password_len, password_hash) ||
312*85732ac8SCy Schubert 	    challenge_response(challenge, password_hash, response))
313e28a4053SRui Paulo 		return -1;
314e28a4053SRui Paulo 	return 0;
31539beb93cSSam Leffler }
31639beb93cSSam Leffler 
31739beb93cSSam Leffler 
31839beb93cSSam Leffler /**
31939beb93cSSam Leffler  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
32039beb93cSSam Leffler  * @password_hash_hash: 16-octet PasswordHashHash (IN)
32139beb93cSSam Leffler  * @nt_response: 24-octet NTResponse (IN)
32239beb93cSSam Leffler  * @master_key: 16-octet MasterKey (OUT)
323e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
32439beb93cSSam Leffler  */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)325e28a4053SRui Paulo int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
32639beb93cSSam Leffler 		   u8 *master_key)
32739beb93cSSam Leffler {
32839beb93cSSam Leffler 	static const u8 magic1[27] = {
32939beb93cSSam Leffler 		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
33039beb93cSSam Leffler 		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
33139beb93cSSam Leffler 		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
33239beb93cSSam Leffler 	};
33339beb93cSSam Leffler 	const unsigned char *addr[3];
33439beb93cSSam Leffler 	const size_t len[3] = { 16, 24, sizeof(magic1) };
33539beb93cSSam Leffler 	u8 hash[SHA1_MAC_LEN];
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 	addr[0] = password_hash_hash;
33839beb93cSSam Leffler 	addr[1] = nt_response;
33939beb93cSSam Leffler 	addr[2] = magic1;
34039beb93cSSam Leffler 
341e28a4053SRui Paulo 	if (sha1_vector(3, addr, len, hash))
342e28a4053SRui Paulo 		return -1;
34339beb93cSSam Leffler 	os_memcpy(master_key, hash, 16);
344e28a4053SRui Paulo 	return 0;
34539beb93cSSam Leffler }
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 
34839beb93cSSam Leffler /**
34939beb93cSSam Leffler  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
35039beb93cSSam Leffler  * @master_key: 16-octet MasterKey (IN)
35139beb93cSSam Leffler  * @session_key: 8-to-16 octet SessionKey (OUT)
35239beb93cSSam Leffler  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
35339beb93cSSam Leffler  * @is_send: IsSend (IN, BOOLEAN)
35439beb93cSSam Leffler  * @is_server: IsServer (IN, BOOLEAN)
355e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
35639beb93cSSam Leffler  */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)357e28a4053SRui Paulo int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
35839beb93cSSam Leffler 			    size_t session_key_len, int is_send,
35939beb93cSSam Leffler 			    int is_server)
36039beb93cSSam Leffler {
36139beb93cSSam Leffler 	static const u8 magic2[84] = {
36239beb93cSSam Leffler 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
36339beb93cSSam Leffler 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
36439beb93cSSam Leffler 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
36539beb93cSSam Leffler 		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
36639beb93cSSam Leffler 		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
36739beb93cSSam Leffler 		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
36839beb93cSSam Leffler 		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
36939beb93cSSam Leffler 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
37039beb93cSSam Leffler 		0x6b, 0x65, 0x79, 0x2e
37139beb93cSSam Leffler 	};
37239beb93cSSam Leffler 	static const u8 magic3[84] = {
37339beb93cSSam Leffler 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
37439beb93cSSam Leffler 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
37539beb93cSSam Leffler 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
37639beb93cSSam Leffler 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
37739beb93cSSam Leffler 		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
37839beb93cSSam Leffler 		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
37939beb93cSSam Leffler 		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
38039beb93cSSam Leffler 		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
38139beb93cSSam Leffler 		0x6b, 0x65, 0x79, 0x2e
38239beb93cSSam Leffler 	};
38339beb93cSSam Leffler 	static const u8 shs_pad1[40] = {
38439beb93cSSam Leffler 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38539beb93cSSam Leffler 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38639beb93cSSam Leffler 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38739beb93cSSam Leffler 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
38839beb93cSSam Leffler 	};
38939beb93cSSam Leffler 
39039beb93cSSam Leffler 	static const u8 shs_pad2[40] = {
39139beb93cSSam Leffler 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
39239beb93cSSam Leffler 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
39339beb93cSSam Leffler 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
39439beb93cSSam Leffler 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
39539beb93cSSam Leffler 	};
39639beb93cSSam Leffler 	u8 digest[SHA1_MAC_LEN];
39739beb93cSSam Leffler 	const unsigned char *addr[4];
39839beb93cSSam Leffler 	const size_t len[4] = { 16, 40, 84, 40 };
39939beb93cSSam Leffler 
40039beb93cSSam Leffler 	addr[0] = master_key;
40139beb93cSSam Leffler 	addr[1] = shs_pad1;
40239beb93cSSam Leffler 	if (is_send) {
40339beb93cSSam Leffler 		addr[2] = is_server ? magic3 : magic2;
40439beb93cSSam Leffler 	} else {
40539beb93cSSam Leffler 		addr[2] = is_server ? magic2 : magic3;
40639beb93cSSam Leffler 	}
40739beb93cSSam Leffler 	addr[3] = shs_pad2;
40839beb93cSSam Leffler 
409e28a4053SRui Paulo 	if (sha1_vector(4, addr, len, digest))
410e28a4053SRui Paulo 		return -1;
41139beb93cSSam Leffler 
41239beb93cSSam Leffler 	if (session_key_len > SHA1_MAC_LEN)
41339beb93cSSam Leffler 		session_key_len = SHA1_MAC_LEN;
41439beb93cSSam Leffler 	os_memcpy(session_key, digest, session_key_len);
415e28a4053SRui Paulo 	return 0;
41639beb93cSSam Leffler }
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 
419325151a3SRui Paulo #ifndef CONFIG_NO_RC4
420325151a3SRui Paulo 
42139beb93cSSam Leffler #define PWBLOCK_LEN 516
42239beb93cSSam Leffler 
42339beb93cSSam Leffler /**
42439beb93cSSam Leffler  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
425f05cddf9SRui Paulo  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
42639beb93cSSam Leffler  * @password_len: Length of password
42739beb93cSSam Leffler  * @password_hash: 16-octet PasswordHash (IN)
42839beb93cSSam Leffler  * @pw_block: 516-byte PwBlock (OUT)
42939beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
43039beb93cSSam Leffler  */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)43139beb93cSSam Leffler int encrypt_pw_block_with_password_hash(
43239beb93cSSam Leffler 	const u8 *password, size_t password_len,
43339beb93cSSam Leffler 	const u8 *password_hash, u8 *pw_block)
43439beb93cSSam Leffler {
435f05cddf9SRui Paulo 	size_t ucs2_len, offset;
43639beb93cSSam Leffler 	u8 *pos;
43739beb93cSSam Leffler 
438f05cddf9SRui Paulo 	os_memset(pw_block, 0, PWBLOCK_LEN);
439f05cddf9SRui Paulo 
440325151a3SRui Paulo 	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
441325151a3SRui Paulo 	    || ucs2_len > 256)
442f05cddf9SRui Paulo 		return -1;
443f05cddf9SRui Paulo 
444f05cddf9SRui Paulo 	offset = (256 - ucs2_len) * 2;
445f05cddf9SRui Paulo 	if (offset != 0) {
446f05cddf9SRui Paulo 		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
44739beb93cSSam Leffler 		if (os_get_random(pw_block, offset) < 0)
44839beb93cSSam Leffler 			return -1;
449f05cddf9SRui Paulo 	}
45039beb93cSSam Leffler 	/*
45139beb93cSSam Leffler 	 * PasswordLength is 4 octets, but since the maximum password length is
45239beb93cSSam Leffler 	 * 256, only first two (in little endian byte order) can be non-zero.
45339beb93cSSam Leffler 	 */
45439beb93cSSam Leffler 	pos = &pw_block[2 * 256];
45539beb93cSSam Leffler 	WPA_PUT_LE16(pos, password_len * 2);
4563157ba21SRui Paulo 	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
45739beb93cSSam Leffler 	return 0;
45839beb93cSSam Leffler }
45939beb93cSSam Leffler 
46039beb93cSSam Leffler 
46139beb93cSSam Leffler /**
46239beb93cSSam Leffler  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
463f05cddf9SRui Paulo  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
46439beb93cSSam Leffler  * @new_password_len: Length of new_password
465f05cddf9SRui Paulo  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
46639beb93cSSam Leffler  * @old_password_len: Length of old_password
46739beb93cSSam Leffler  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
46839beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
46939beb93cSSam Leffler  */
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)47039beb93cSSam Leffler int new_password_encrypted_with_old_nt_password_hash(
47139beb93cSSam Leffler 	const u8 *new_password, size_t new_password_len,
47239beb93cSSam Leffler 	const u8 *old_password, size_t old_password_len,
47339beb93cSSam Leffler 	u8 *encrypted_pw_block)
47439beb93cSSam Leffler {
47539beb93cSSam Leffler 	u8 password_hash[16];
47639beb93cSSam Leffler 
477e28a4053SRui Paulo 	if (nt_password_hash(old_password, old_password_len, password_hash))
478e28a4053SRui Paulo 		return -1;
47939beb93cSSam Leffler 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
48039beb93cSSam Leffler 						password_hash,
48139beb93cSSam Leffler 						encrypted_pw_block))
48239beb93cSSam Leffler 		return -1;
48339beb93cSSam Leffler 	return 0;
48439beb93cSSam Leffler }
48539beb93cSSam Leffler 
486325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */
487325151a3SRui Paulo 
48839beb93cSSam Leffler 
48939beb93cSSam Leffler /**
49039beb93cSSam Leffler  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
49139beb93cSSam Leffler  * @password_hash: 16-octer PasswordHash (IN)
49239beb93cSSam Leffler  * @block: 16-octet Block (IN)
49339beb93cSSam Leffler  * @cypher: 16-octer Cypher (OUT)
494*85732ac8SCy Schubert  * Returns: 0 on success, -1 on failure
49539beb93cSSam Leffler  */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)496*85732ac8SCy Schubert int nt_password_hash_encrypted_with_block(const u8 *password_hash,
49739beb93cSSam Leffler 					  const u8 *block, u8 *cypher)
49839beb93cSSam Leffler {
499*85732ac8SCy Schubert 	if (des_encrypt(password_hash, block, cypher) < 0 ||
500*85732ac8SCy Schubert 	    des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
501*85732ac8SCy Schubert 		return -1;
502*85732ac8SCy Schubert 	return 0;
50339beb93cSSam Leffler }
50439beb93cSSam Leffler 
50539beb93cSSam Leffler 
50639beb93cSSam Leffler /**
50739beb93cSSam Leffler  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
508f05cddf9SRui Paulo  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
50939beb93cSSam Leffler  * @new_password_len: Length of new_password
510f05cddf9SRui Paulo  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
51139beb93cSSam Leffler  * @old_password_len: Length of old_password
51239beb93cSSam Leffler  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
513e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
51439beb93cSSam Leffler  */
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)515e28a4053SRui Paulo int old_nt_password_hash_encrypted_with_new_nt_password_hash(
51639beb93cSSam Leffler 	const u8 *new_password, size_t new_password_len,
51739beb93cSSam Leffler 	const u8 *old_password, size_t old_password_len,
51839beb93cSSam Leffler 	u8 *encrypted_password_hash)
51939beb93cSSam Leffler {
52039beb93cSSam Leffler 	u8 old_password_hash[16], new_password_hash[16];
52139beb93cSSam Leffler 
522e28a4053SRui Paulo 	if (nt_password_hash(old_password, old_password_len,
523e28a4053SRui Paulo 			     old_password_hash) ||
524e28a4053SRui Paulo 	    nt_password_hash(new_password, new_password_len,
525*85732ac8SCy Schubert 			     new_password_hash) ||
52639beb93cSSam Leffler 	    nt_password_hash_encrypted_with_block(old_password_hash,
52739beb93cSSam Leffler 						  new_password_hash,
528*85732ac8SCy Schubert 						  encrypted_password_hash))
529*85732ac8SCy Schubert 		return -1;
530e28a4053SRui Paulo 	return 0;
53139beb93cSSam Leffler }
532