xref: /dflybsd-src/contrib/wpa_supplicant/src/crypto/ms_funcs.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
33ff40c12SJohn Marino  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer 
116d49e1aeSJan Lentfer #include "common.h"
126d49e1aeSJan Lentfer #include "sha1.h"
136d49e1aeSJan Lentfer #include "ms_funcs.h"
146d49e1aeSJan Lentfer #include "crypto.h"
153ff40c12SJohn Marino 
163ff40c12SJohn Marino /**
173ff40c12SJohn Marino  * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
183ff40c12SJohn Marino  * @utf8_string: UTF-8 string (IN)
193ff40c12SJohn Marino  * @utf8_string_len: Length of utf8_string (IN)
203ff40c12SJohn Marino  * @ucs2_buffer: UCS-2 buffer (OUT)
213ff40c12SJohn Marino  * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
223ff40c12SJohn Marino  * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
233ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
243ff40c12SJohn Marino  */
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)253ff40c12SJohn Marino static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
263ff40c12SJohn Marino                         u8 *ucs2_buffer, size_t ucs2_buffer_size,
273ff40c12SJohn Marino                         size_t *ucs2_string_size)
283ff40c12SJohn Marino {
293ff40c12SJohn Marino 	size_t i, j;
303ff40c12SJohn Marino 
313ff40c12SJohn Marino 	for (i = 0, j = 0; i < utf8_string_len; i++) {
323ff40c12SJohn Marino 		u8 c = utf8_string[i];
333ff40c12SJohn Marino 		if (j >= ucs2_buffer_size) {
343ff40c12SJohn Marino 			/* input too long */
353ff40c12SJohn Marino 			return -1;
363ff40c12SJohn Marino 		}
373ff40c12SJohn Marino 		if (c <= 0x7F) {
383ff40c12SJohn Marino 			WPA_PUT_LE16(ucs2_buffer + j, c);
393ff40c12SJohn Marino 			j += 2;
403ff40c12SJohn Marino 		} else if (i == utf8_string_len - 1 ||
413ff40c12SJohn Marino 			   j >= ucs2_buffer_size - 1) {
423ff40c12SJohn Marino 			/* incomplete surrogate */
433ff40c12SJohn Marino 			return -1;
443ff40c12SJohn Marino 		} else {
453ff40c12SJohn Marino 			u8 c2 = utf8_string[++i];
463ff40c12SJohn Marino 			if ((c & 0xE0) == 0xC0) {
473ff40c12SJohn Marino 				/* two-byte encoding */
483ff40c12SJohn Marino 				WPA_PUT_LE16(ucs2_buffer + j,
493ff40c12SJohn Marino 					     ((c & 0x1F) << 6) | (c2 & 0x3F));
503ff40c12SJohn Marino 				j += 2;
51*a1157835SDaniel Fojt 			} else if (i == utf8_string_len - 1 ||
523ff40c12SJohn Marino 				   j >= ucs2_buffer_size - 1) {
533ff40c12SJohn Marino 				/* incomplete surrogate */
543ff40c12SJohn Marino 				return -1;
553ff40c12SJohn Marino 			} else {
563ff40c12SJohn Marino 				/* three-byte encoding */
573ff40c12SJohn Marino 				u8 c3 = utf8_string[++i];
583ff40c12SJohn Marino 				WPA_PUT_LE16(ucs2_buffer + j,
593ff40c12SJohn Marino 					     ((c & 0xF) << 12) |
603ff40c12SJohn Marino 					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
61*a1157835SDaniel Fojt 				j += 2;
623ff40c12SJohn Marino 			}
633ff40c12SJohn Marino 		}
643ff40c12SJohn Marino 	}
653ff40c12SJohn Marino 
663ff40c12SJohn Marino 	if (ucs2_string_size)
673ff40c12SJohn Marino 		*ucs2_string_size = j / 2;
683ff40c12SJohn Marino 	return 0;
693ff40c12SJohn Marino }
706d49e1aeSJan Lentfer 
716d49e1aeSJan Lentfer 
726d49e1aeSJan Lentfer /**
736d49e1aeSJan Lentfer  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
746d49e1aeSJan Lentfer  * @peer_challenge: 16-octet PeerChallenge (IN)
756d49e1aeSJan Lentfer  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
766d49e1aeSJan Lentfer  * @username: 0-to-256-char UserName (IN)
776d49e1aeSJan Lentfer  * @username_len: Length of username
786d49e1aeSJan Lentfer  * @challenge: 8-octet Challenge (OUT)
793ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
806d49e1aeSJan Lentfer  */
challenge_hash(const u8 * peer_challenge,const u8 * auth_challenge,const u8 * username,size_t username_len,u8 * challenge)81*a1157835SDaniel Fojt int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82*a1157835SDaniel Fojt 		   const u8 *username, size_t username_len, u8 *challenge)
836d49e1aeSJan Lentfer {
846d49e1aeSJan Lentfer 	u8 hash[SHA1_MAC_LEN];
856d49e1aeSJan Lentfer 	const unsigned char *addr[3];
866d49e1aeSJan Lentfer 	size_t len[3];
876d49e1aeSJan Lentfer 
886d49e1aeSJan Lentfer 	addr[0] = peer_challenge;
896d49e1aeSJan Lentfer 	len[0] = 16;
906d49e1aeSJan Lentfer 	addr[1] = auth_challenge;
916d49e1aeSJan Lentfer 	len[1] = 16;
926d49e1aeSJan Lentfer 	addr[2] = username;
936d49e1aeSJan Lentfer 	len[2] = username_len;
946d49e1aeSJan Lentfer 
953ff40c12SJohn Marino 	if (sha1_vector(3, addr, len, hash))
963ff40c12SJohn Marino 		return -1;
976d49e1aeSJan Lentfer 	os_memcpy(challenge, hash, 8);
983ff40c12SJohn Marino 	return 0;
996d49e1aeSJan Lentfer }
1006d49e1aeSJan Lentfer 
1016d49e1aeSJan Lentfer 
1026d49e1aeSJan Lentfer /**
1036d49e1aeSJan Lentfer  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
1043ff40c12SJohn Marino  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1056d49e1aeSJan Lentfer  * @password_len: Length of password
1066d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (OUT)
1073ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
1086d49e1aeSJan Lentfer  */
nt_password_hash(const u8 * password,size_t password_len,u8 * password_hash)1093ff40c12SJohn Marino int nt_password_hash(const u8 *password, size_t password_len,
1106d49e1aeSJan Lentfer 		      u8 *password_hash)
1116d49e1aeSJan Lentfer {
1126d49e1aeSJan Lentfer 	u8 buf[512], *pos;
1133ff40c12SJohn Marino 	size_t len, max_len;
1146d49e1aeSJan Lentfer 
1153ff40c12SJohn Marino 	max_len = sizeof(buf);
1163ff40c12SJohn Marino 	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
1173ff40c12SJohn Marino 		return -1;
1186d49e1aeSJan Lentfer 
1193ff40c12SJohn Marino 	len *= 2;
1206d49e1aeSJan Lentfer 	pos = buf;
1213ff40c12SJohn Marino 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
1226d49e1aeSJan Lentfer }
1236d49e1aeSJan Lentfer 
1246d49e1aeSJan Lentfer 
1256d49e1aeSJan Lentfer /**
1266d49e1aeSJan Lentfer  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
1276d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (IN)
1286d49e1aeSJan Lentfer  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
1293ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
1306d49e1aeSJan Lentfer  */
hash_nt_password_hash(const u8 * password_hash,u8 * password_hash_hash)1313ff40c12SJohn Marino int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
1326d49e1aeSJan Lentfer {
1336d49e1aeSJan Lentfer 	size_t len = 16;
1343ff40c12SJohn Marino 	return md4_vector(1, &password_hash, &len, password_hash_hash);
1356d49e1aeSJan Lentfer }
1366d49e1aeSJan Lentfer 
1376d49e1aeSJan Lentfer 
1386d49e1aeSJan Lentfer /**
1396d49e1aeSJan Lentfer  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
1406d49e1aeSJan Lentfer  * @challenge: 8-octet Challenge (IN)
1416d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (IN)
1426d49e1aeSJan Lentfer  * @response: 24-octet Response (OUT)
143*a1157835SDaniel Fojt  * Returns: 0 on success, -1 on failure
1446d49e1aeSJan Lentfer  */
challenge_response(const u8 * challenge,const u8 * password_hash,u8 * response)145*a1157835SDaniel Fojt int challenge_response(const u8 *challenge, const u8 *password_hash,
1466d49e1aeSJan Lentfer 		       u8 *response)
1476d49e1aeSJan Lentfer {
1486d49e1aeSJan Lentfer 	u8 zpwd[7];
149*a1157835SDaniel Fojt 
150*a1157835SDaniel Fojt 	if (des_encrypt(challenge, password_hash, response) < 0 ||
151*a1157835SDaniel Fojt 	    des_encrypt(challenge, password_hash + 7, response + 8) < 0)
152*a1157835SDaniel Fojt 		return -1;
1536d49e1aeSJan Lentfer 	zpwd[0] = password_hash[14];
1546d49e1aeSJan Lentfer 	zpwd[1] = password_hash[15];
1556d49e1aeSJan Lentfer 	os_memset(zpwd + 2, 0, 5);
156*a1157835SDaniel Fojt 	return des_encrypt(challenge, zpwd, response + 16);
1576d49e1aeSJan Lentfer }
1586d49e1aeSJan Lentfer 
1596d49e1aeSJan Lentfer 
1606d49e1aeSJan Lentfer /**
1616d49e1aeSJan Lentfer  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
1626d49e1aeSJan Lentfer  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1636d49e1aeSJan Lentfer  * @peer_challenge: 16-octet PeerChallenge (IN)
1646d49e1aeSJan Lentfer  * @username: 0-to-256-char UserName (IN)
1656d49e1aeSJan Lentfer  * @username_len: Length of username
1663ff40c12SJohn Marino  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
1676d49e1aeSJan Lentfer  * @password_len: Length of password
1686d49e1aeSJan Lentfer  * @response: 24-octet Response (OUT)
1693ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
1706d49e1aeSJan Lentfer  */
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)1713ff40c12SJohn Marino int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
1726d49e1aeSJan Lentfer 			 const u8 *username, size_t username_len,
1736d49e1aeSJan Lentfer 			 const u8 *password, size_t password_len,
1746d49e1aeSJan Lentfer 			 u8 *response)
1756d49e1aeSJan Lentfer {
1766d49e1aeSJan Lentfer 	u8 challenge[8];
1776d49e1aeSJan Lentfer 	u8 password_hash[16];
1786d49e1aeSJan Lentfer 
1793ff40c12SJohn Marino 	if (challenge_hash(peer_challenge, auth_challenge, username,
180*a1157835SDaniel Fojt 			   username_len, challenge) ||
181*a1157835SDaniel Fojt 	    nt_password_hash(password, password_len, password_hash) ||
182*a1157835SDaniel Fojt 	    challenge_response(challenge, password_hash, response))
1833ff40c12SJohn Marino 		return -1;
1843ff40c12SJohn Marino 	return 0;
1856d49e1aeSJan Lentfer }
1866d49e1aeSJan Lentfer 
1876d49e1aeSJan Lentfer 
1886d49e1aeSJan Lentfer /**
1896d49e1aeSJan Lentfer  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
1906d49e1aeSJan Lentfer  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
1916d49e1aeSJan Lentfer  * @peer_challenge: 16-octet PeerChallenge (IN)
1926d49e1aeSJan Lentfer  * @username: 0-to-256-char UserName (IN)
1936d49e1aeSJan Lentfer  * @username_len: Length of username
1946d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (IN)
1956d49e1aeSJan Lentfer  * @response: 24-octet Response (OUT)
1963ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
1976d49e1aeSJan Lentfer  */
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)1983ff40c12SJohn Marino int generate_nt_response_pwhash(const u8 *auth_challenge,
1996d49e1aeSJan Lentfer 				const u8 *peer_challenge,
2006d49e1aeSJan Lentfer 				const u8 *username, size_t username_len,
2016d49e1aeSJan Lentfer 				const u8 *password_hash,
2026d49e1aeSJan Lentfer 				u8 *response)
2036d49e1aeSJan Lentfer {
2046d49e1aeSJan Lentfer 	u8 challenge[8];
2056d49e1aeSJan Lentfer 
2063ff40c12SJohn Marino 	if (challenge_hash(peer_challenge, auth_challenge,
2073ff40c12SJohn Marino 			   username, username_len,
208*a1157835SDaniel Fojt 			   challenge) ||
209*a1157835SDaniel Fojt 	    challenge_response(challenge, password_hash, response))
2103ff40c12SJohn Marino 		return -1;
2113ff40c12SJohn Marino 	return 0;
2126d49e1aeSJan Lentfer }
2136d49e1aeSJan Lentfer 
2146d49e1aeSJan Lentfer 
2156d49e1aeSJan Lentfer /**
2166d49e1aeSJan Lentfer  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
2176d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (IN)
2186d49e1aeSJan Lentfer  * @nt_response: 24-octet NT-Response (IN)
2196d49e1aeSJan Lentfer  * @peer_challenge: 16-octet PeerChallenge (IN)
2206d49e1aeSJan Lentfer  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2216d49e1aeSJan Lentfer  * @username: 0-to-256-char UserName (IN)
2226d49e1aeSJan Lentfer  * @username_len: Length of username
2236d49e1aeSJan Lentfer  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2246d49e1aeSJan Lentfer  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2253ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
2266d49e1aeSJan Lentfer  */
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)2273ff40c12SJohn Marino int generate_authenticator_response_pwhash(
2286d49e1aeSJan Lentfer 	const u8 *password_hash,
2296d49e1aeSJan Lentfer 	const u8 *peer_challenge, const u8 *auth_challenge,
2306d49e1aeSJan Lentfer 	const u8 *username, size_t username_len,
2316d49e1aeSJan Lentfer 	const u8 *nt_response, u8 *response)
2326d49e1aeSJan Lentfer {
2336d49e1aeSJan Lentfer 	static const u8 magic1[39] = {
2346d49e1aeSJan Lentfer 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
2356d49e1aeSJan Lentfer 		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
2366d49e1aeSJan Lentfer 		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
2376d49e1aeSJan Lentfer 		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
2386d49e1aeSJan Lentfer 	};
2396d49e1aeSJan Lentfer 	static const u8 magic2[41] = {
2406d49e1aeSJan Lentfer 		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
2416d49e1aeSJan Lentfer 		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
2426d49e1aeSJan Lentfer 		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
2436d49e1aeSJan Lentfer 		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
2446d49e1aeSJan Lentfer 		0x6E
2456d49e1aeSJan Lentfer 	};
2466d49e1aeSJan Lentfer 
2476d49e1aeSJan Lentfer 	u8 password_hash_hash[16], challenge[8];
2486d49e1aeSJan Lentfer 	const unsigned char *addr1[3];
2496d49e1aeSJan Lentfer 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
2506d49e1aeSJan Lentfer 	const unsigned char *addr2[3];
2516d49e1aeSJan Lentfer 	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
2526d49e1aeSJan Lentfer 
2536d49e1aeSJan Lentfer 	addr1[0] = password_hash_hash;
2546d49e1aeSJan Lentfer 	addr1[1] = nt_response;
2556d49e1aeSJan Lentfer 	addr1[2] = magic1;
2566d49e1aeSJan Lentfer 
2576d49e1aeSJan Lentfer 	addr2[0] = response;
2586d49e1aeSJan Lentfer 	addr2[1] = challenge;
2596d49e1aeSJan Lentfer 	addr2[2] = magic2;
2606d49e1aeSJan Lentfer 
261*a1157835SDaniel Fojt 	if (hash_nt_password_hash(password_hash, password_hash_hash) ||
262*a1157835SDaniel Fojt 	    sha1_vector(3, addr1, len1, response) ||
263*a1157835SDaniel Fojt 	    challenge_hash(peer_challenge, auth_challenge, username,
2643ff40c12SJohn Marino 			   username_len, challenge))
2653ff40c12SJohn Marino 		return -1;
2663ff40c12SJohn Marino 	return sha1_vector(3, addr2, len2, response);
2676d49e1aeSJan Lentfer }
2686d49e1aeSJan Lentfer 
2696d49e1aeSJan Lentfer 
2706d49e1aeSJan Lentfer /**
2716d49e1aeSJan Lentfer  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
2723ff40c12SJohn Marino  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
2736d49e1aeSJan Lentfer  * @password_len: Length of password
2746d49e1aeSJan Lentfer  * @nt_response: 24-octet NT-Response (IN)
2756d49e1aeSJan Lentfer  * @peer_challenge: 16-octet PeerChallenge (IN)
2766d49e1aeSJan Lentfer  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
2776d49e1aeSJan Lentfer  * @username: 0-to-256-char UserName (IN)
2786d49e1aeSJan Lentfer  * @username_len: Length of username
2796d49e1aeSJan Lentfer  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
2806d49e1aeSJan Lentfer  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
2813ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
2826d49e1aeSJan Lentfer  */
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)2833ff40c12SJohn Marino int generate_authenticator_response(const u8 *password, size_t password_len,
2846d49e1aeSJan Lentfer 				    const u8 *peer_challenge,
2856d49e1aeSJan Lentfer 				    const u8 *auth_challenge,
2866d49e1aeSJan Lentfer 				    const u8 *username, size_t username_len,
2876d49e1aeSJan Lentfer 				    const u8 *nt_response, u8 *response)
2886d49e1aeSJan Lentfer {
2896d49e1aeSJan Lentfer 	u8 password_hash[16];
2903ff40c12SJohn Marino 	if (nt_password_hash(password, password_len, password_hash))
2913ff40c12SJohn Marino 		return -1;
2923ff40c12SJohn Marino 	return generate_authenticator_response_pwhash(
2933ff40c12SJohn Marino 		password_hash, peer_challenge, auth_challenge,
2943ff40c12SJohn Marino 		username, username_len, nt_response, response);
2956d49e1aeSJan Lentfer }
2966d49e1aeSJan Lentfer 
2976d49e1aeSJan Lentfer 
2986d49e1aeSJan Lentfer /**
2996d49e1aeSJan Lentfer  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
3006d49e1aeSJan Lentfer  * @challenge: 8-octet Challenge (IN)
3013ff40c12SJohn Marino  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
3026d49e1aeSJan Lentfer  * @password_len: Length of password
3036d49e1aeSJan Lentfer  * @response: 24-octet Response (OUT)
3043ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
3056d49e1aeSJan Lentfer  */
nt_challenge_response(const u8 * challenge,const u8 * password,size_t password_len,u8 * response)3063ff40c12SJohn Marino int nt_challenge_response(const u8 *challenge, const u8 *password,
3076d49e1aeSJan Lentfer 			  size_t password_len, u8 *response)
3086d49e1aeSJan Lentfer {
3096d49e1aeSJan Lentfer 	u8 password_hash[16];
310*a1157835SDaniel Fojt 
311*a1157835SDaniel Fojt 	if (nt_password_hash(password, password_len, password_hash) ||
312*a1157835SDaniel Fojt 	    challenge_response(challenge, password_hash, response))
3133ff40c12SJohn Marino 		return -1;
3143ff40c12SJohn Marino 	return 0;
3156d49e1aeSJan Lentfer }
3166d49e1aeSJan Lentfer 
3176d49e1aeSJan Lentfer 
3186d49e1aeSJan Lentfer /**
3196d49e1aeSJan Lentfer  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
3206d49e1aeSJan Lentfer  * @password_hash_hash: 16-octet PasswordHashHash (IN)
3216d49e1aeSJan Lentfer  * @nt_response: 24-octet NTResponse (IN)
3226d49e1aeSJan Lentfer  * @master_key: 16-octet MasterKey (OUT)
3233ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
3246d49e1aeSJan Lentfer  */
get_master_key(const u8 * password_hash_hash,const u8 * nt_response,u8 * master_key)3253ff40c12SJohn Marino int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
3266d49e1aeSJan Lentfer 		   u8 *master_key)
3276d49e1aeSJan Lentfer {
3286d49e1aeSJan Lentfer 	static const u8 magic1[27] = {
3296d49e1aeSJan Lentfer 		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
3306d49e1aeSJan Lentfer 		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
3316d49e1aeSJan Lentfer 		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
3326d49e1aeSJan Lentfer 	};
3336d49e1aeSJan Lentfer 	const unsigned char *addr[3];
3346d49e1aeSJan Lentfer 	const size_t len[3] = { 16, 24, sizeof(magic1) };
3356d49e1aeSJan Lentfer 	u8 hash[SHA1_MAC_LEN];
3366d49e1aeSJan Lentfer 
3376d49e1aeSJan Lentfer 	addr[0] = password_hash_hash;
3386d49e1aeSJan Lentfer 	addr[1] = nt_response;
3396d49e1aeSJan Lentfer 	addr[2] = magic1;
3406d49e1aeSJan Lentfer 
3413ff40c12SJohn Marino 	if (sha1_vector(3, addr, len, hash))
3423ff40c12SJohn Marino 		return -1;
3436d49e1aeSJan Lentfer 	os_memcpy(master_key, hash, 16);
3443ff40c12SJohn Marino 	return 0;
3456d49e1aeSJan Lentfer }
3466d49e1aeSJan Lentfer 
3476d49e1aeSJan Lentfer 
3486d49e1aeSJan Lentfer /**
3496d49e1aeSJan Lentfer  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
3506d49e1aeSJan Lentfer  * @master_key: 16-octet MasterKey (IN)
3516d49e1aeSJan Lentfer  * @session_key: 8-to-16 octet SessionKey (OUT)
3526d49e1aeSJan Lentfer  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
3536d49e1aeSJan Lentfer  * @is_send: IsSend (IN, BOOLEAN)
3546d49e1aeSJan Lentfer  * @is_server: IsServer (IN, BOOLEAN)
3553ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
3566d49e1aeSJan Lentfer  */
get_asymetric_start_key(const u8 * master_key,u8 * session_key,size_t session_key_len,int is_send,int is_server)3573ff40c12SJohn Marino int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
3586d49e1aeSJan Lentfer 			    size_t session_key_len, int is_send,
3596d49e1aeSJan Lentfer 			    int is_server)
3606d49e1aeSJan Lentfer {
3616d49e1aeSJan Lentfer 	static const u8 magic2[84] = {
3626d49e1aeSJan Lentfer 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3636d49e1aeSJan Lentfer 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3646d49e1aeSJan Lentfer 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3656d49e1aeSJan Lentfer 		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
3666d49e1aeSJan Lentfer 		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
3676d49e1aeSJan Lentfer 		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
3686d49e1aeSJan Lentfer 		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3696d49e1aeSJan Lentfer 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3706d49e1aeSJan Lentfer 		0x6b, 0x65, 0x79, 0x2e
3716d49e1aeSJan Lentfer 	};
3726d49e1aeSJan Lentfer 	static const u8 magic3[84] = {
3736d49e1aeSJan Lentfer 		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
3746d49e1aeSJan Lentfer 		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
3756d49e1aeSJan Lentfer 		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
3766d49e1aeSJan Lentfer 		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
3776d49e1aeSJan Lentfer 		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
3786d49e1aeSJan Lentfer 		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
3796d49e1aeSJan Lentfer 		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
3806d49e1aeSJan Lentfer 		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
3816d49e1aeSJan Lentfer 		0x6b, 0x65, 0x79, 0x2e
3826d49e1aeSJan Lentfer 	};
3836d49e1aeSJan Lentfer 	static const u8 shs_pad1[40] = {
3846d49e1aeSJan Lentfer 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3856d49e1aeSJan Lentfer 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3866d49e1aeSJan Lentfer 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3876d49e1aeSJan Lentfer 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3886d49e1aeSJan Lentfer 	};
3896d49e1aeSJan Lentfer 
3906d49e1aeSJan Lentfer 	static const u8 shs_pad2[40] = {
3916d49e1aeSJan Lentfer 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3926d49e1aeSJan Lentfer 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3936d49e1aeSJan Lentfer 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
3946d49e1aeSJan Lentfer 		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
3956d49e1aeSJan Lentfer 	};
3966d49e1aeSJan Lentfer 	u8 digest[SHA1_MAC_LEN];
3976d49e1aeSJan Lentfer 	const unsigned char *addr[4];
3986d49e1aeSJan Lentfer 	const size_t len[4] = { 16, 40, 84, 40 };
3996d49e1aeSJan Lentfer 
4006d49e1aeSJan Lentfer 	addr[0] = master_key;
4016d49e1aeSJan Lentfer 	addr[1] = shs_pad1;
4026d49e1aeSJan Lentfer 	if (is_send) {
4036d49e1aeSJan Lentfer 		addr[2] = is_server ? magic3 : magic2;
4046d49e1aeSJan Lentfer 	} else {
4056d49e1aeSJan Lentfer 		addr[2] = is_server ? magic2 : magic3;
4066d49e1aeSJan Lentfer 	}
4076d49e1aeSJan Lentfer 	addr[3] = shs_pad2;
4086d49e1aeSJan Lentfer 
4093ff40c12SJohn Marino 	if (sha1_vector(4, addr, len, digest))
4103ff40c12SJohn Marino 		return -1;
4116d49e1aeSJan Lentfer 
4126d49e1aeSJan Lentfer 	if (session_key_len > SHA1_MAC_LEN)
4136d49e1aeSJan Lentfer 		session_key_len = SHA1_MAC_LEN;
4146d49e1aeSJan Lentfer 	os_memcpy(session_key, digest, session_key_len);
4153ff40c12SJohn Marino 	return 0;
4166d49e1aeSJan Lentfer }
4176d49e1aeSJan Lentfer 
4186d49e1aeSJan Lentfer 
419*a1157835SDaniel Fojt #ifndef CONFIG_NO_RC4
420*a1157835SDaniel Fojt 
4216d49e1aeSJan Lentfer #define PWBLOCK_LEN 516
4226d49e1aeSJan Lentfer 
4236d49e1aeSJan Lentfer /**
4246d49e1aeSJan Lentfer  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
4253ff40c12SJohn Marino  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
4266d49e1aeSJan Lentfer  * @password_len: Length of password
4276d49e1aeSJan Lentfer  * @password_hash: 16-octet PasswordHash (IN)
4286d49e1aeSJan Lentfer  * @pw_block: 516-byte PwBlock (OUT)
4296d49e1aeSJan Lentfer  * Returns: 0 on success, -1 on failure
4306d49e1aeSJan Lentfer  */
encrypt_pw_block_with_password_hash(const u8 * password,size_t password_len,const u8 * password_hash,u8 * pw_block)4316d49e1aeSJan Lentfer int encrypt_pw_block_with_password_hash(
4326d49e1aeSJan Lentfer 	const u8 *password, size_t password_len,
4336d49e1aeSJan Lentfer 	const u8 *password_hash, u8 *pw_block)
4346d49e1aeSJan Lentfer {
4353ff40c12SJohn Marino 	size_t ucs2_len, offset;
4366d49e1aeSJan Lentfer 	u8 *pos;
4376d49e1aeSJan Lentfer 
4383ff40c12SJohn Marino 	os_memset(pw_block, 0, PWBLOCK_LEN);
4393ff40c12SJohn Marino 
440*a1157835SDaniel Fojt 	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
441*a1157835SDaniel Fojt 	    || ucs2_len > 256)
4423ff40c12SJohn Marino 		return -1;
4433ff40c12SJohn Marino 
4443ff40c12SJohn Marino 	offset = (256 - ucs2_len) * 2;
4453ff40c12SJohn Marino 	if (offset != 0) {
4463ff40c12SJohn Marino 		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
4476d49e1aeSJan Lentfer 		if (os_get_random(pw_block, offset) < 0)
4486d49e1aeSJan Lentfer 			return -1;
4493ff40c12SJohn Marino 	}
4506d49e1aeSJan Lentfer 	/*
4516d49e1aeSJan Lentfer 	 * PasswordLength is 4 octets, but since the maximum password length is
4526d49e1aeSJan Lentfer 	 * 256, only first two (in little endian byte order) can be non-zero.
4536d49e1aeSJan Lentfer 	 */
4546d49e1aeSJan Lentfer 	pos = &pw_block[2 * 256];
4556d49e1aeSJan Lentfer 	WPA_PUT_LE16(pos, password_len * 2);
4566d49e1aeSJan Lentfer 	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
4576d49e1aeSJan Lentfer 	return 0;
4586d49e1aeSJan Lentfer }
4596d49e1aeSJan Lentfer 
4606d49e1aeSJan Lentfer 
4616d49e1aeSJan Lentfer /**
4626d49e1aeSJan Lentfer  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
4633ff40c12SJohn Marino  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
4646d49e1aeSJan Lentfer  * @new_password_len: Length of new_password
4653ff40c12SJohn Marino  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
4666d49e1aeSJan Lentfer  * @old_password_len: Length of old_password
4676d49e1aeSJan Lentfer  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
4686d49e1aeSJan Lentfer  * Returns: 0 on success, -1 on failure
4696d49e1aeSJan Lentfer  */
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)4706d49e1aeSJan Lentfer int new_password_encrypted_with_old_nt_password_hash(
4716d49e1aeSJan Lentfer 	const u8 *new_password, size_t new_password_len,
4726d49e1aeSJan Lentfer 	const u8 *old_password, size_t old_password_len,
4736d49e1aeSJan Lentfer 	u8 *encrypted_pw_block)
4746d49e1aeSJan Lentfer {
4756d49e1aeSJan Lentfer 	u8 password_hash[16];
4766d49e1aeSJan Lentfer 
4773ff40c12SJohn Marino 	if (nt_password_hash(old_password, old_password_len, password_hash))
4783ff40c12SJohn Marino 		return -1;
4796d49e1aeSJan Lentfer 	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
4806d49e1aeSJan Lentfer 						password_hash,
4816d49e1aeSJan Lentfer 						encrypted_pw_block))
4826d49e1aeSJan Lentfer 		return -1;
4836d49e1aeSJan Lentfer 	return 0;
4846d49e1aeSJan Lentfer }
4856d49e1aeSJan Lentfer 
486*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
487*a1157835SDaniel Fojt 
4886d49e1aeSJan Lentfer 
4896d49e1aeSJan Lentfer /**
4906d49e1aeSJan Lentfer  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
4916d49e1aeSJan Lentfer  * @password_hash: 16-octer PasswordHash (IN)
4926d49e1aeSJan Lentfer  * @block: 16-octet Block (IN)
4936d49e1aeSJan Lentfer  * @cypher: 16-octer Cypher (OUT)
494*a1157835SDaniel Fojt  * Returns: 0 on success, -1 on failure
4956d49e1aeSJan Lentfer  */
nt_password_hash_encrypted_with_block(const u8 * password_hash,const u8 * block,u8 * cypher)496*a1157835SDaniel Fojt int nt_password_hash_encrypted_with_block(const u8 *password_hash,
4976d49e1aeSJan Lentfer 					  const u8 *block, u8 *cypher)
4986d49e1aeSJan Lentfer {
499*a1157835SDaniel Fojt 	if (des_encrypt(password_hash, block, cypher) < 0 ||
500*a1157835SDaniel Fojt 	    des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
501*a1157835SDaniel Fojt 		return -1;
502*a1157835SDaniel Fojt 	return 0;
5036d49e1aeSJan Lentfer }
5046d49e1aeSJan Lentfer 
5056d49e1aeSJan Lentfer 
5066d49e1aeSJan Lentfer /**
5076d49e1aeSJan Lentfer  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
5083ff40c12SJohn Marino  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
5096d49e1aeSJan Lentfer  * @new_password_len: Length of new_password
5103ff40c12SJohn Marino  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
5116d49e1aeSJan Lentfer  * @old_password_len: Length of old_password
5126d49e1aeSJan Lentfer  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
5133ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
5146d49e1aeSJan Lentfer  */
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)5153ff40c12SJohn Marino int old_nt_password_hash_encrypted_with_new_nt_password_hash(
5166d49e1aeSJan Lentfer 	const u8 *new_password, size_t new_password_len,
5176d49e1aeSJan Lentfer 	const u8 *old_password, size_t old_password_len,
5186d49e1aeSJan Lentfer 	u8 *encrypted_password_hash)
5196d49e1aeSJan Lentfer {
5206d49e1aeSJan Lentfer 	u8 old_password_hash[16], new_password_hash[16];
5216d49e1aeSJan Lentfer 
5223ff40c12SJohn Marino 	if (nt_password_hash(old_password, old_password_len,
5233ff40c12SJohn Marino 			     old_password_hash) ||
5243ff40c12SJohn Marino 	    nt_password_hash(new_password, new_password_len,
525*a1157835SDaniel Fojt 			     new_password_hash) ||
5266d49e1aeSJan Lentfer 	    nt_password_hash_encrypted_with_block(old_password_hash,
5276d49e1aeSJan Lentfer 						  new_password_hash,
528*a1157835SDaniel Fojt 						  encrypted_password_hash))
529*a1157835SDaniel Fojt 		return -1;
5303ff40c12SJohn Marino 	return 0;
5316d49e1aeSJan Lentfer }
532