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