xref: /netbsd-src/external/bsd/wpa/dist/src/crypto/ms_funcs.c (revision 0a73ee0a32b4208ab171f89f408b38fd4c664291)
18dbcf02cSchristos /*
28dbcf02cSchristos  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3e604d861Schristos  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos  *
5e604d861Schristos  * This software may be distributed under the terms of the BSD license.
6e604d861Schristos  * See README for more details.
78dbcf02cSchristos  */
88dbcf02cSchristos 
98dbcf02cSchristos #include "includes.h"
108dbcf02cSchristos 
118dbcf02cSchristos #include "common.h"
128dbcf02cSchristos #include "sha1.h"
138dbcf02cSchristos #include "ms_funcs.h"
148dbcf02cSchristos #include "crypto.h"
158dbcf02cSchristos 
16111b9fd8Schristos /**
17111b9fd8Schristos  * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18111b9fd8Schristos  * @utf8_string: UTF-8 string (IN)
19111b9fd8Schristos  * @utf8_string_len: Length of utf8_string (IN)
20111b9fd8Schristos  * @ucs2_buffer: UCS-2 buffer (OUT)
21111b9fd8Schristos  * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
22111b9fd8Schristos  * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
23111b9fd8Schristos  * Returns: 0 on success, -1 on failure
24111b9fd8Schristos  */
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)25111b9fd8Schristos static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
26111b9fd8Schristos                         u8 *ucs2_buffer, size_t ucs2_buffer_size,
27111b9fd8Schristos                         size_t *ucs2_string_size)
28111b9fd8Schristos {
29111b9fd8Schristos 	size_t i, j;
30111b9fd8Schristos 
31111b9fd8Schristos 	for (i = 0, j = 0; i < utf8_string_len; i++) {
32111b9fd8Schristos 		u8 c = utf8_string[i];
33111b9fd8Schristos 		if (j >= ucs2_buffer_size) {
34111b9fd8Schristos 			/* input too long */
35111b9fd8Schristos 			return -1;
36111b9fd8Schristos 		}
37111b9fd8Schristos 		if (c <= 0x7F) {
38111b9fd8Schristos 			WPA_PUT_LE16(ucs2_buffer + j, c);
39111b9fd8Schristos 			j += 2;
40111b9fd8Schristos 		} else if (i == utf8_string_len - 1 ||
41111b9fd8Schristos 			   j >= ucs2_buffer_size - 1) {
42111b9fd8Schristos 			/* incomplete surrogate */
43111b9fd8Schristos 			return -1;
44111b9fd8Schristos 		} else {
45111b9fd8Schristos 			u8 c2 = utf8_string[++i];
46111b9fd8Schristos 			if ((c & 0xE0) == 0xC0) {
47111b9fd8Schristos 				/* two-byte encoding */
48111b9fd8Schristos 				WPA_PUT_LE16(ucs2_buffer + j,
49111b9fd8Schristos 					     ((c & 0x1F) << 6) | (c2 & 0x3F));
50111b9fd8Schristos 				j += 2;
5136ebd06eSchristos 			} else if (i == utf8_string_len - 1 ||
52111b9fd8Schristos 				   j >= ucs2_buffer_size - 1) {
53111b9fd8Schristos 				/* incomplete surrogate */
54111b9fd8Schristos 				return -1;
55111b9fd8Schristos 			} else {
56111b9fd8Schristos 				/* three-byte encoding */
57111b9fd8Schristos 				u8 c3 = utf8_string[++i];
58111b9fd8Schristos 				WPA_PUT_LE16(ucs2_buffer + j,
59111b9fd8Schristos 					     ((c & 0xF) << 12) |
60111b9fd8Schristos 					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
613c260e60Schristos 				j += 2;
62111b9fd8Schristos 			}
63111b9fd8Schristos 		}
64111b9fd8Schristos 	}
65111b9fd8Schristos 
66111b9fd8Schristos 	if (ucs2_string_size)
67111b9fd8Schristos 		*ucs2_string_size = j / 2;
68111b9fd8Schristos 	return 0;
69111b9fd8Schristos }
70111b9fd8Schristos 
718dbcf02cSchristos 
728dbcf02cSchristos /**
738dbcf02cSchristos  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
748dbcf02cSchristos  * @peer_challenge: 16-octet PeerChallenge (IN)
758dbcf02cSchristos  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
768dbcf02cSchristos  * @username: 0-to-256-char UserName (IN)
778dbcf02cSchristos  * @username_len: Length of username
788dbcf02cSchristos  * @challenge: 8-octet Challenge (OUT)
798dbcf02cSchristos  * Returns: 0 on success, -1 on failure
808dbcf02cSchristos  */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)8136ebd06eSchristos int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
8236ebd06eSchristos 		   const u8 *username, size_t username_len, u8 *challenge)
838dbcf02cSchristos {
848dbcf02cSchristos 	u8 hash[SHA1_MAC_LEN];
858dbcf02cSchristos 	const unsigned char *addr[3];
868dbcf02cSchristos 	size_t len[3];
878dbcf02cSchristos 
888dbcf02cSchristos 	addr[0] = peer_challenge;
898dbcf02cSchristos 	len[0] = 16;
908dbcf02cSchristos 	addr[1] = auth_challenge;
918dbcf02cSchristos 	len[1] = 16;
928dbcf02cSchristos 	addr[2] = username;
938dbcf02cSchristos 	len[2] = username_len;
948dbcf02cSchristos 
958dbcf02cSchristos 	if (sha1_vector(3, addr, len, hash))
968dbcf02cSchristos 		return -1;
978dbcf02cSchristos 	os_memcpy(challenge, hash, 8);
988dbcf02cSchristos 	return 0;
998dbcf02cSchristos }
1008dbcf02cSchristos 
1018dbcf02cSchristos 
1028dbcf02cSchristos /**
1038dbcf02cSchristos  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104111b9fd8Schristos  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1058dbcf02cSchristos  * @password_len: Length of password
1068dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (OUT)
1078dbcf02cSchristos  * Returns: 0 on success, -1 on failure
1088dbcf02cSchristos  */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)1098dbcf02cSchristos int nt_password_hash(const u8 *password, size_t password_len,
1108dbcf02cSchristos 		      u8 *password_hash)
1118dbcf02cSchristos {
1128dbcf02cSchristos 	u8 buf[512], *pos;
113111b9fd8Schristos 	size_t len, max_len;
1148dbcf02cSchristos 
115111b9fd8Schristos 	max_len = sizeof(buf);
116111b9fd8Schristos 	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117111b9fd8Schristos 		return -1;
1188dbcf02cSchristos 
119111b9fd8Schristos 	len *= 2;
1208dbcf02cSchristos 	pos = buf;
1218dbcf02cSchristos 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
1228dbcf02cSchristos }
1238dbcf02cSchristos 
1248dbcf02cSchristos 
1258dbcf02cSchristos /**
1268dbcf02cSchristos  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
1278dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (IN)
1288dbcf02cSchristos  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
1298dbcf02cSchristos  * Returns: 0 on success, -1 on failure
1308dbcf02cSchristos  */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)1318dbcf02cSchristos int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
1328dbcf02cSchristos {
1338dbcf02cSchristos 	size_t len = 16;
1348dbcf02cSchristos 	return md4_vector(1, &password_hash, &len, password_hash_hash);
1358dbcf02cSchristos }
1368dbcf02cSchristos 
1378dbcf02cSchristos 
1388dbcf02cSchristos /**
1398dbcf02cSchristos  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
1408dbcf02cSchristos  * @challenge: 8-octet Challenge (IN)
1418dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (IN)
1428dbcf02cSchristos  * @response: 24-octet Response (OUT)
143*0a73ee0aSchristos  * Returns: 0 on success, -1 on failure
1448dbcf02cSchristos  */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)145*0a73ee0aSchristos int challenge_response(const u8 *challenge, const u8 *password_hash,
1468dbcf02cSchristos 		       u8 *response)
1478dbcf02cSchristos {
1488dbcf02cSchristos 	u8 zpwd[7];
149*0a73ee0aSchristos 
150*0a73ee0aSchristos 	if (des_encrypt(challenge, password_hash, response) < 0 ||
151*0a73ee0aSchristos 	    des_encrypt(challenge, password_hash + 7, response + 8) < 0)
152*0a73ee0aSchristos 		return -1;
1538dbcf02cSchristos 	zpwd[0] = password_hash[14];
1548dbcf02cSchristos 	zpwd[1] = password_hash[15];
1558dbcf02cSchristos 	os_memset(zpwd + 2, 0, 5);
156*0a73ee0aSchristos 	return des_encrypt(challenge, zpwd, response + 16);
1578dbcf02cSchristos }
1588dbcf02cSchristos 
1598dbcf02cSchristos 
1608dbcf02cSchristos /**
1618dbcf02cSchristos  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
1628dbcf02cSchristos  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1638dbcf02cSchristos  * @peer_challenge: 16-octet PeerChallenge (IN)
1648dbcf02cSchristos  * @username: 0-to-256-char UserName (IN)
1658dbcf02cSchristos  * @username_len: Length of username
166111b9fd8Schristos  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1678dbcf02cSchristos  * @password_len: Length of password
1688dbcf02cSchristos  * @response: 24-octet Response (OUT)
1698dbcf02cSchristos  * Returns: 0 on success, -1 on failure
1708dbcf02cSchristos  */
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)1718dbcf02cSchristos int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
1728dbcf02cSchristos 			 const u8 *username, size_t username_len,
1738dbcf02cSchristos 			 const u8 *password, size_t password_len,
1748dbcf02cSchristos 			 u8 *response)
1758dbcf02cSchristos {
1768dbcf02cSchristos 	u8 challenge[8];
1778dbcf02cSchristos 	u8 password_hash[16];
1788dbcf02cSchristos 
179e604d861Schristos 	if (challenge_hash(peer_challenge, auth_challenge, username,
18036ebd06eSchristos 			   username_len, challenge) ||
181*0a73ee0aSchristos 	    nt_password_hash(password, password_len, password_hash) ||
182*0a73ee0aSchristos 	    challenge_response(challenge, password_hash, response))
1838dbcf02cSchristos 		return -1;
1848dbcf02cSchristos 	return 0;
1858dbcf02cSchristos }
1868dbcf02cSchristos 
1878dbcf02cSchristos 
1888dbcf02cSchristos /**
1898dbcf02cSchristos  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
1908dbcf02cSchristos  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1918dbcf02cSchristos  * @peer_challenge: 16-octet PeerChallenge (IN)
1928dbcf02cSchristos  * @username: 0-to-256-char UserName (IN)
1938dbcf02cSchristos  * @username_len: Length of username
1948dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (IN)
1958dbcf02cSchristos  * @response: 24-octet Response (OUT)
1968dbcf02cSchristos  * Returns: 0 on success, -1 on failure
1978dbcf02cSchristos  */
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)1988dbcf02cSchristos int generate_nt_response_pwhash(const u8 *auth_challenge,
1998dbcf02cSchristos 				const u8 *peer_challenge,
2008dbcf02cSchristos 				const u8 *username, size_t username_len,
2018dbcf02cSchristos 				const u8 *password_hash,
2028dbcf02cSchristos 				u8 *response)
2038dbcf02cSchristos {
2048dbcf02cSchristos 	u8 challenge[8];
2058dbcf02cSchristos 
2068dbcf02cSchristos 	if (challenge_hash(peer_challenge, auth_challenge,
2078dbcf02cSchristos 			   username, username_len,
208*0a73ee0aSchristos 			   challenge) ||
209*0a73ee0aSchristos 	    challenge_response(challenge, password_hash, response))
2108dbcf02cSchristos 		return -1;
2118dbcf02cSchristos 	return 0;
2128dbcf02cSchristos }
2138dbcf02cSchristos 
2148dbcf02cSchristos 
2158dbcf02cSchristos /**
2168dbcf02cSchristos  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
2178dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (IN)
2188dbcf02cSchristos  * @nt_response: 24-octet NT-Response (IN)
2198dbcf02cSchristos  * @peer_challenge: 16-octet PeerChallenge (IN)
2208dbcf02cSchristos  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2218dbcf02cSchristos  * @username: 0-to-256-char UserName (IN)
2228dbcf02cSchristos  * @username_len: Length of username
2238dbcf02cSchristos  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2248dbcf02cSchristos  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2258dbcf02cSchristos  * Returns: 0 on success, -1 on failure
2268dbcf02cSchristos  */
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)2278dbcf02cSchristos int generate_authenticator_response_pwhash(
2288dbcf02cSchristos 	const u8 *password_hash,
2298dbcf02cSchristos 	const u8 *peer_challenge, const u8 *auth_challenge,
2308dbcf02cSchristos 	const u8 *username, size_t username_len,
2318dbcf02cSchristos 	const u8 *nt_response, u8 *response)
2328dbcf02cSchristos {
2338dbcf02cSchristos 	static const u8 magic1[39] = {
2348dbcf02cSchristos 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
2358dbcf02cSchristos 		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
2368dbcf02cSchristos 		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
2378dbcf02cSchristos 		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
2388dbcf02cSchristos 	};
2398dbcf02cSchristos 	static const u8 magic2[41] = {
2408dbcf02cSchristos 		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
2418dbcf02cSchristos 		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
2428dbcf02cSchristos 		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
2438dbcf02cSchristos 		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
2448dbcf02cSchristos 		0x6E
2458dbcf02cSchristos 	};
2468dbcf02cSchristos 
2478dbcf02cSchristos 	u8 password_hash_hash[16], challenge[8];
2488dbcf02cSchristos 	const unsigned char *addr1[3];
2498dbcf02cSchristos 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
2508dbcf02cSchristos 	const unsigned char *addr2[3];
2518dbcf02cSchristos 	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
2528dbcf02cSchristos 
2538dbcf02cSchristos 	addr1[0] = password_hash_hash;
2548dbcf02cSchristos 	addr1[1] = nt_response;
2558dbcf02cSchristos 	addr1[2] = magic1;
2568dbcf02cSchristos 
2578dbcf02cSchristos 	addr2[0] = response;
2588dbcf02cSchristos 	addr2[1] = challenge;
2598dbcf02cSchristos 	addr2[2] = magic2;
2608dbcf02cSchristos 
26136ebd06eSchristos 	if (hash_nt_password_hash(password_hash, password_hash_hash) ||
26236ebd06eSchristos 	    sha1_vector(3, addr1, len1, response) ||
26336ebd06eSchristos 	    challenge_hash(peer_challenge, auth_challenge, username,
264e604d861Schristos 			   username_len, challenge))
265e604d861Schristos 		return -1;
2668dbcf02cSchristos 	return sha1_vector(3, addr2, len2, response);
2678dbcf02cSchristos }
2688dbcf02cSchristos 
2698dbcf02cSchristos 
2708dbcf02cSchristos /**
2718dbcf02cSchristos  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
272111b9fd8Schristos  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
2738dbcf02cSchristos  * @password_len: Length of password
2748dbcf02cSchristos  * @nt_response: 24-octet NT-Response (IN)
2758dbcf02cSchristos  * @peer_challenge: 16-octet PeerChallenge (IN)
2768dbcf02cSchristos  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2778dbcf02cSchristos  * @username: 0-to-256-char UserName (IN)
2788dbcf02cSchristos  * @username_len: Length of username
2798dbcf02cSchristos  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2808dbcf02cSchristos  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2818dbcf02cSchristos  * Returns: 0 on success, -1 on failure
2828dbcf02cSchristos  */
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)2838dbcf02cSchristos int generate_authenticator_response(const u8 *password, size_t password_len,
2848dbcf02cSchristos 				    const u8 *peer_challenge,
2858dbcf02cSchristos 				    const u8 *auth_challenge,
2868dbcf02cSchristos 				    const u8 *username, size_t username_len,
2878dbcf02cSchristos 				    const u8 *nt_response, u8 *response)
2888dbcf02cSchristos {
2898dbcf02cSchristos 	u8 password_hash[16];
2908dbcf02cSchristos 	if (nt_password_hash(password, password_len, password_hash))
2918dbcf02cSchristos 		return -1;
2928dbcf02cSchristos 	return generate_authenticator_response_pwhash(
2938dbcf02cSchristos 		password_hash, peer_challenge, auth_challenge,
2948dbcf02cSchristos 		username, username_len, nt_response, response);
2958dbcf02cSchristos }
2968dbcf02cSchristos 
2978dbcf02cSchristos 
2988dbcf02cSchristos /**
2998dbcf02cSchristos  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
3008dbcf02cSchristos  * @challenge: 8-octet Challenge (IN)
301111b9fd8Schristos  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
3028dbcf02cSchristos  * @password_len: Length of password
3038dbcf02cSchristos  * @response: 24-octet Response (OUT)
3048dbcf02cSchristos  * Returns: 0 on success, -1 on failure
3058dbcf02cSchristos  */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)3068dbcf02cSchristos int nt_challenge_response(const u8 *challenge, const u8 *password,
3078dbcf02cSchristos 			  size_t password_len, u8 *response)
3088dbcf02cSchristos {
3098dbcf02cSchristos 	u8 password_hash[16];
310*0a73ee0aSchristos 
311*0a73ee0aSchristos 	if (nt_password_hash(password, password_len, password_hash) ||
312*0a73ee0aSchristos 	    challenge_response(challenge, password_hash, response))
3138dbcf02cSchristos 		return -1;
3148dbcf02cSchristos 	return 0;
3158dbcf02cSchristos }
3168dbcf02cSchristos 
3178dbcf02cSchristos 
3188dbcf02cSchristos /**
3198dbcf02cSchristos  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
3208dbcf02cSchristos  * @password_hash_hash: 16-octet PasswordHashHash (IN)
3218dbcf02cSchristos  * @nt_response: 24-octet NTResponse (IN)
3228dbcf02cSchristos  * @master_key: 16-octet MasterKey (OUT)
3238dbcf02cSchristos  * Returns: 0 on success, -1 on failure
3248dbcf02cSchristos  */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)3258dbcf02cSchristos int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
3268dbcf02cSchristos 		   u8 *master_key)
3278dbcf02cSchristos {
3288dbcf02cSchristos 	static const u8 magic1[27] = {
3298dbcf02cSchristos 		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
3308dbcf02cSchristos 		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
3318dbcf02cSchristos 		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
3328dbcf02cSchristos 	};
3338dbcf02cSchristos 	const unsigned char *addr[3];
3348dbcf02cSchristos 	const size_t len[3] = { 16, 24, sizeof(magic1) };
3358dbcf02cSchristos 	u8 hash[SHA1_MAC_LEN];
3368dbcf02cSchristos 
3378dbcf02cSchristos 	addr[0] = password_hash_hash;
3388dbcf02cSchristos 	addr[1] = nt_response;
3398dbcf02cSchristos 	addr[2] = magic1;
3408dbcf02cSchristos 
3418dbcf02cSchristos 	if (sha1_vector(3, addr, len, hash))
3428dbcf02cSchristos 		return -1;
3438dbcf02cSchristos 	os_memcpy(master_key, hash, 16);
3448dbcf02cSchristos 	return 0;
3458dbcf02cSchristos }
3468dbcf02cSchristos 
3478dbcf02cSchristos 
3488dbcf02cSchristos /**
3498dbcf02cSchristos  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
3508dbcf02cSchristos  * @master_key: 16-octet MasterKey (IN)
3518dbcf02cSchristos  * @session_key: 8-to-16 octet SessionKey (OUT)
3528dbcf02cSchristos  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
3538dbcf02cSchristos  * @is_send: IsSend (IN, BOOLEAN)
3548dbcf02cSchristos  * @is_server: IsServer (IN, BOOLEAN)
3558dbcf02cSchristos  * Returns: 0 on success, -1 on failure
3568dbcf02cSchristos  */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)3578dbcf02cSchristos int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
3588dbcf02cSchristos 			    size_t session_key_len, int is_send,
3598dbcf02cSchristos 			    int is_server)
3608dbcf02cSchristos {
3618dbcf02cSchristos 	static const u8 magic2[84] = {
3628dbcf02cSchristos 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3638dbcf02cSchristos 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3648dbcf02cSchristos 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3658dbcf02cSchristos 		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
3668dbcf02cSchristos 		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
3678dbcf02cSchristos 		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
3688dbcf02cSchristos 		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3698dbcf02cSchristos 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3708dbcf02cSchristos 		0x6b, 0x65, 0x79, 0x2e
3718dbcf02cSchristos 	};
3728dbcf02cSchristos 	static const u8 magic3[84] = {
3738dbcf02cSchristos 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3748dbcf02cSchristos 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3758dbcf02cSchristos 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3768dbcf02cSchristos 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3778dbcf02cSchristos 		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
3788dbcf02cSchristos 		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
3798dbcf02cSchristos 		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
3808dbcf02cSchristos 		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
3818dbcf02cSchristos 		0x6b, 0x65, 0x79, 0x2e
3828dbcf02cSchristos 	};
3838dbcf02cSchristos 	static const u8 shs_pad1[40] = {
3848dbcf02cSchristos 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3858dbcf02cSchristos 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3868dbcf02cSchristos 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3878dbcf02cSchristos 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3888dbcf02cSchristos 	};
3898dbcf02cSchristos 
3908dbcf02cSchristos 	static const u8 shs_pad2[40] = {
3918dbcf02cSchristos 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3928dbcf02cSchristos 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3938dbcf02cSchristos 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3948dbcf02cSchristos 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
3958dbcf02cSchristos 	};
3968dbcf02cSchristos 	u8 digest[SHA1_MAC_LEN];
3978dbcf02cSchristos 	const unsigned char *addr[4];
3988dbcf02cSchristos 	const size_t len[4] = { 16, 40, 84, 40 };
3998dbcf02cSchristos 
4008dbcf02cSchristos 	addr[0] = master_key;
4018dbcf02cSchristos 	addr[1] = shs_pad1;
4028dbcf02cSchristos 	if (is_send) {
4038dbcf02cSchristos 		addr[2] = is_server ? magic3 : magic2;
4048dbcf02cSchristos 	} else {
4058dbcf02cSchristos 		addr[2] = is_server ? magic2 : magic3;
4068dbcf02cSchristos 	}
4078dbcf02cSchristos 	addr[3] = shs_pad2;
4088dbcf02cSchristos 
4098dbcf02cSchristos 	if (sha1_vector(4, addr, len, digest))
4108dbcf02cSchristos 		return -1;
4118dbcf02cSchristos 
4128dbcf02cSchristos 	if (session_key_len > SHA1_MAC_LEN)
4138dbcf02cSchristos 		session_key_len = SHA1_MAC_LEN;
4148dbcf02cSchristos 	os_memcpy(session_key, digest, session_key_len);
4158dbcf02cSchristos 	return 0;
4168dbcf02cSchristos }
4178dbcf02cSchristos 
4188dbcf02cSchristos 
41936ebd06eSchristos #ifndef CONFIG_NO_RC4
42036ebd06eSchristos 
4218dbcf02cSchristos #define PWBLOCK_LEN 516
4228dbcf02cSchristos 
4238dbcf02cSchristos /**
4248dbcf02cSchristos  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
425111b9fd8Schristos  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
4268dbcf02cSchristos  * @password_len: Length of password
4278dbcf02cSchristos  * @password_hash: 16-octet PasswordHash (IN)
4288dbcf02cSchristos  * @pw_block: 516-byte PwBlock (OUT)
4298dbcf02cSchristos  * Returns: 0 on success, -1 on failure
4308dbcf02cSchristos  */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)4318dbcf02cSchristos int encrypt_pw_block_with_password_hash(
4328dbcf02cSchristos 	const u8 *password, size_t password_len,
4338dbcf02cSchristos 	const u8 *password_hash, u8 *pw_block)
4348dbcf02cSchristos {
435111b9fd8Schristos 	size_t ucs2_len, offset;
4368dbcf02cSchristos 	u8 *pos;
4378dbcf02cSchristos 
438111b9fd8Schristos 	os_memset(pw_block, 0, PWBLOCK_LEN);
439111b9fd8Schristos 
44036ebd06eSchristos 	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
44136ebd06eSchristos 	    || ucs2_len > 256)
442111b9fd8Schristos 		return -1;
443111b9fd8Schristos 
444111b9fd8Schristos 	offset = (256 - ucs2_len) * 2;
445111b9fd8Schristos 	if (offset != 0) {
446111b9fd8Schristos 		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
4478dbcf02cSchristos 		if (os_get_random(pw_block, offset) < 0)
4488dbcf02cSchristos 			return -1;
449111b9fd8Schristos 	}
4508dbcf02cSchristos 	/*
4518dbcf02cSchristos 	 * PasswordLength is 4 octets, but since the maximum password length is
4528dbcf02cSchristos 	 * 256, only first two (in little endian byte order) can be non-zero.
4538dbcf02cSchristos 	 */
4548dbcf02cSchristos 	pos = &pw_block[2 * 256];
4558dbcf02cSchristos 	WPA_PUT_LE16(pos, password_len * 2);
4568dbcf02cSchristos 	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
4578dbcf02cSchristos 	return 0;
4588dbcf02cSchristos }
4598dbcf02cSchristos 
4608dbcf02cSchristos 
4618dbcf02cSchristos /**
4628dbcf02cSchristos  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
463111b9fd8Schristos  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
4648dbcf02cSchristos  * @new_password_len: Length of new_password
465111b9fd8Schristos  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
4668dbcf02cSchristos  * @old_password_len: Length of old_password
4678dbcf02cSchristos  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
4688dbcf02cSchristos  * Returns: 0 on success, -1 on failure
4698dbcf02cSchristos  */
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)4708dbcf02cSchristos int new_password_encrypted_with_old_nt_password_hash(
4718dbcf02cSchristos 	const u8 *new_password, size_t new_password_len,
4728dbcf02cSchristos 	const u8 *old_password, size_t old_password_len,
4738dbcf02cSchristos 	u8 *encrypted_pw_block)
4748dbcf02cSchristos {
4758dbcf02cSchristos 	u8 password_hash[16];
4768dbcf02cSchristos 
4778dbcf02cSchristos 	if (nt_password_hash(old_password, old_password_len, password_hash))
4788dbcf02cSchristos 		return -1;
4798dbcf02cSchristos 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
4808dbcf02cSchristos 						password_hash,
4818dbcf02cSchristos 						encrypted_pw_block))
4828dbcf02cSchristos 		return -1;
4838dbcf02cSchristos 	return 0;
4848dbcf02cSchristos }
4858dbcf02cSchristos 
48636ebd06eSchristos #endif /* CONFIG_NO_RC4 */
48736ebd06eSchristos 
4888dbcf02cSchristos 
4898dbcf02cSchristos /**
4908dbcf02cSchristos  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
4918dbcf02cSchristos  * @password_hash: 16-octer PasswordHash (IN)
4928dbcf02cSchristos  * @block: 16-octet Block (IN)
4938dbcf02cSchristos  * @cypher: 16-octer Cypher (OUT)
494*0a73ee0aSchristos  * Returns: 0 on success, -1 on failure
4958dbcf02cSchristos  */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)496*0a73ee0aSchristos int nt_password_hash_encrypted_with_block(const u8 *password_hash,
4978dbcf02cSchristos 					  const u8 *block, u8 *cypher)
4988dbcf02cSchristos {
499*0a73ee0aSchristos 	if (des_encrypt(password_hash, block, cypher) < 0 ||
500*0a73ee0aSchristos 	    des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
501*0a73ee0aSchristos 		return -1;
502*0a73ee0aSchristos 	return 0;
5038dbcf02cSchristos }
5048dbcf02cSchristos 
5058dbcf02cSchristos 
5068dbcf02cSchristos /**
5078dbcf02cSchristos  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
508111b9fd8Schristos  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
5098dbcf02cSchristos  * @new_password_len: Length of new_password
510111b9fd8Schristos  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
5118dbcf02cSchristos  * @old_password_len: Length of old_password
5128dbcf02cSchristos  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
5138dbcf02cSchristos  * Returns: 0 on success, -1 on failure
5148dbcf02cSchristos  */
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)5158dbcf02cSchristos int old_nt_password_hash_encrypted_with_new_nt_password_hash(
5168dbcf02cSchristos 	const u8 *new_password, size_t new_password_len,
5178dbcf02cSchristos 	const u8 *old_password, size_t old_password_len,
5188dbcf02cSchristos 	u8 *encrypted_password_hash)
5198dbcf02cSchristos {
5208dbcf02cSchristos 	u8 old_password_hash[16], new_password_hash[16];
5218dbcf02cSchristos 
5228dbcf02cSchristos 	if (nt_password_hash(old_password, old_password_len,
5238dbcf02cSchristos 			     old_password_hash) ||
5248dbcf02cSchristos 	    nt_password_hash(new_password, new_password_len,
525*0a73ee0aSchristos 			     new_password_hash) ||
5268dbcf02cSchristos 	    nt_password_hash_encrypted_with_block(old_password_hash,
5278dbcf02cSchristos 						  new_password_hash,
528*0a73ee0aSchristos 						  encrypted_password_hash))
529*0a73ee0aSchristos 		return -1;
5308dbcf02cSchristos 	return 0;
5318dbcf02cSchristos }
532