ms_funcs.c revision 61d9df3e62aaa0e87ad05452fcb95142159a17b6
13d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/* 23d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 33d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> 43d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * 53d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * This software may be distributed under the terms of the BSD license. 63d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * See README for more details. 73d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */ 83d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 93d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "includes.h" 10565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman 11565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman#include "common.h" 123d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "sha1.h" 133d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "ms_funcs.h" 143d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman#include "crypto.h" 153d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 163d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/** 173d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding 18686775deca8b8685eb90801495880e3abdd844c2Chris Lattner * @utf8_string: UTF-8 string (IN) 193d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @utf8_string_len: Length of utf8_string (IN) 203b844ba7d5be205a9b4f5f0b0d1b7978977f4b8cChandler Carruth * @ucs2_buffer: UCS-2 buffer (OUT) 213d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @ucs2_buffer_size: Length of UCS-2 buffer (IN) 223d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string 233d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * Returns: 0 on success, -1 on failure 243d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */ 253d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohmanstatic int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len, 263d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman u8 *ucs2_buffer, size_t ucs2_buffer_size, 273d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman size_t *ucs2_string_size) 283d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman{ 29c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany size_t i, j; 303d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 3114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne for (i = 0, j = 0; i < utf8_string_len; i++) { 323d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman u8 c = utf8_string[i]; 333d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman if (j >= ucs2_buffer_size) { 343d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman /* input too long */ 353d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman return -1; 363d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman } 373d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman if (c <= 0x7F) { 38b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren WPA_PUT_LE16(ucs2_buffer + j, c); 39b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren j += 2; 40b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren } else if (i == utf8_string_len - 1 || 41b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren j >= ucs2_buffer_size - 1) { 42b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren /* incomplete surrogate */ 43b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren return -1; 44b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren } else { 45b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren u8 c2 = utf8_string[++i]; 463d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman if ((c & 0xE0) == 0xC0) { 473d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman /* two-byte encoding */ 483d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman WPA_PUT_LE16(ucs2_buffer + j, 493d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman ((c & 0x1F) << 6) | (c2 & 0x3F)); 50c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany j += 2; 513d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman } else if (i == utf8_string_len || 520b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman j >= ucs2_buffer_size - 1) { 533d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman /* incomplete surrogate */ 542d7cb069fe101da3971a07900ff583380bcac184Duncan Sands return -1; 552d7cb069fe101da3971a07900ff583380bcac184Duncan Sands } else { 562d7cb069fe101da3971a07900ff583380bcac184Duncan Sands /* three-byte encoding */ 57b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren u8 c3 = utf8_string[++i]; 58b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren WPA_PUT_LE16(ucs2_buffer + j, 593d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman ((c & 0xF) << 12) | 60b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren ((c2 & 0x3F) << 6) | (c3 & 0x3F)); 61b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren } 62b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren } 63b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren } 643d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 65b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman if (ucs2_string_size) 66b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman *ucs2_string_size = j / 2; 67b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman return 0; 68b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman} 693d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 70224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman 713d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman/** 72224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2 73224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @peer_challenge: 16-octet PeerChallenge (IN) 74224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 75224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @username: 0-to-256-char UserName (IN) 76224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * @username_len: Length of username 773d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman * @challenge: 8-octet Challenge (OUT) 78224d75972a836b06e2ca708d1eafdac6f762c487Dan Gohman * Returns: 0 on success, -1 on failure 793d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman */ 80b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohmanstatic int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, 81b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman const u8 *username, size_t username_len, 82b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman u8 *challenge) 83b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman{ 84b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman u8 hash[SHA1_MAC_LEN]; 85b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman const unsigned char *addr[3]; 86b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman size_t len[3]; 873d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 883d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman addr[0] = peer_challenge; 89c9fe6056e4ce8ffad1ef439fca3318a5faf1c075Kostya Serebryany len[0] = 16; 900b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman addr[1] = auth_challenge; 910b5c4fc2ae3b503c2b1f354bf52b718aa50a6aeeDan Gohman len[1] = 16; 923d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman addr[2] = username; 933d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman len[2] = username_len; 94565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman 95565cc44bea707ff3865fbeb731e4790dd9874786Dan Gohman if (sha1_vector(3, addr, len, hash)) 963d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman return -1; 978cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany os_memcpy(challenge, hash, 8); 988cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany return 0; 998cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany} 1008cb4a070d491ddd671b049110cc8d0accb08b905Kostya Serebryany 101b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman 102b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman/** 103b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 104b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9bDan Gohman * @password: 0-to-256-unicode-char Password (IN; UTF-8) 105b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_len: Length of password 106b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (OUT) 107b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * Returns: 0 on success, -1 on failure 108b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */ 109b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renint nt_password_hash(const u8 *password, size_t password_len, 110b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren u8 *password_hash) 111b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{ 1123d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman u8 buf[512], *pos; 1133d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman size_t len, max_len; 1143d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman 1153d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman max_len = sizeof(buf); 1163d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0) 117b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren return -1; 118b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren 119b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren len *= 2; 120b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren pos = buf; 121b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren return md4_vector(1, (const u8 **) &pos, &len, password_hash); 122b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren} 123b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren 124b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren 125b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren/** 126b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 127b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (IN) 128b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash_hash: 16-octet PasswordHashHash (OUT) 129b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * Returns: 0 on success, -1 on failure 130b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */ 131b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renint hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) 132b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{ 133b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren size_t len = 16; 134b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren return md4_vector(1, &password_hash, &len, password_hash_hash); 135b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren} 136b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren 137b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren 138b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren/** 139b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5 140b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @challenge: 8-octet Challenge (IN) 141b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @password_hash: 16-octet PasswordHash (IN) 142b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren * @response: 24-octet Response (OUT) 143b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren */ 144b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Renvoid challenge_response(const u8 *challenge, const u8 *password_hash, 145b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren u8 *response) 146b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren{ 147b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren u8 zpwd[7]; 148b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren des_encrypt(challenge, password_hash, response); 149b37a73d5c6a0c8bb1f6e363d3b53980e4fa0ceadManman Ren des_encrypt(challenge, password_hash + 7, response + 8); 1503d5aff5d3036b0ff09d114857cd2276134b3d8c9Dan Gohman zpwd[0] = password_hash[14]; 151 zpwd[1] = password_hash[15]; 152 os_memset(zpwd + 2, 0, 5); 153 des_encrypt(challenge, zpwd, response + 16); 154} 155 156 157/** 158 * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 159 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 160 * @peer_challenge: 16-octet PeerChallenge (IN) 161 * @username: 0-to-256-char UserName (IN) 162 * @username_len: Length of username 163 * @password: 0-to-256-unicode-char Password (IN; UTF-8) 164 * @password_len: Length of password 165 * @response: 24-octet Response (OUT) 166 * Returns: 0 on success, -1 on failure 167 */ 168int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, 169 const u8 *username, size_t username_len, 170 const u8 *password, size_t password_len, 171 u8 *response) 172{ 173 u8 challenge[8]; 174 u8 password_hash[16]; 175 176 if (challenge_hash(peer_challenge, auth_challenge, username, 177 username_len, challenge)) 178 return -1; 179 if (nt_password_hash(password, password_len, password_hash)) 180 return -1; 181 challenge_response(challenge, password_hash, response); 182 return 0; 183} 184 185 186/** 187 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1 188 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 189 * @peer_challenge: 16-octet PeerChallenge (IN) 190 * @username: 0-to-256-char UserName (IN) 191 * @username_len: Length of username 192 * @password_hash: 16-octet PasswordHash (IN) 193 * @response: 24-octet Response (OUT) 194 * Returns: 0 on success, -1 on failure 195 */ 196int generate_nt_response_pwhash(const u8 *auth_challenge, 197 const u8 *peer_challenge, 198 const u8 *username, size_t username_len, 199 const u8 *password_hash, 200 u8 *response) 201{ 202 u8 challenge[8]; 203 204 if (challenge_hash(peer_challenge, auth_challenge, 205 username, username_len, 206 challenge)) 207 return -1; 208 challenge_response(challenge, password_hash, response); 209 return 0; 210} 211 212 213/** 214 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 215 * @password_hash: 16-octet PasswordHash (IN) 216 * @nt_response: 24-octet NT-Response (IN) 217 * @peer_challenge: 16-octet PeerChallenge (IN) 218 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 219 * @username: 0-to-256-char UserName (IN) 220 * @username_len: Length of username 221 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually 222 * encoded as a 42-octet ASCII string (S=hexdump_of_response) 223 * Returns: 0 on success, -1 on failure 224 */ 225int generate_authenticator_response_pwhash( 226 const u8 *password_hash, 227 const u8 *peer_challenge, const u8 *auth_challenge, 228 const u8 *username, size_t username_len, 229 const u8 *nt_response, u8 *response) 230{ 231 static const u8 magic1[39] = { 232 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 233 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 234 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 235 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 236 }; 237 static const u8 magic2[41] = { 238 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 239 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 240 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 241 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 242 0x6E 243 }; 244 245 u8 password_hash_hash[16], challenge[8]; 246 const unsigned char *addr1[3]; 247 const size_t len1[3] = { 16, 24, sizeof(magic1) }; 248 const unsigned char *addr2[3]; 249 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; 250 251 addr1[0] = password_hash_hash; 252 addr1[1] = nt_response; 253 addr1[2] = magic1; 254 255 addr2[0] = response; 256 addr2[1] = challenge; 257 addr2[2] = magic2; 258 259 if (hash_nt_password_hash(password_hash, password_hash_hash)) 260 return -1; 261 if (sha1_vector(3, addr1, len1, response)) 262 return -1; 263 264 if (challenge_hash(peer_challenge, auth_challenge, username, 265 username_len, challenge)) 266 return -1; 267 return sha1_vector(3, addr2, len2, response); 268} 269 270 271/** 272 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 273 * @password: 0-to-256-unicode-char Password (IN; UTF-8) 274 * @password_len: Length of password 275 * @nt_response: 24-octet NT-Response (IN) 276 * @peer_challenge: 16-octet PeerChallenge (IN) 277 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 278 * @username: 0-to-256-char UserName (IN) 279 * @username_len: Length of username 280 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually 281 * encoded as a 42-octet ASCII string (S=hexdump_of_response) 282 * Returns: 0 on success, -1 on failure 283 */ 284int generate_authenticator_response(const u8 *password, size_t password_len, 285 const u8 *peer_challenge, 286 const u8 *auth_challenge, 287 const u8 *username, size_t username_len, 288 const u8 *nt_response, u8 *response) 289{ 290 u8 password_hash[16]; 291 if (nt_password_hash(password, password_len, password_hash)) 292 return -1; 293 return generate_authenticator_response_pwhash( 294 password_hash, peer_challenge, auth_challenge, 295 username, username_len, nt_response, response); 296} 297 298 299/** 300 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 301 * @challenge: 8-octet Challenge (IN) 302 * @password: 0-to-256-unicode-char Password (IN; UTF-8) 303 * @password_len: Length of password 304 * @response: 24-octet Response (OUT) 305 * Returns: 0 on success, -1 on failure 306 */ 307int nt_challenge_response(const u8 *challenge, const u8 *password, 308 size_t password_len, u8 *response) 309{ 310 u8 password_hash[16]; 311 if (nt_password_hash(password, password_len, password_hash)) 312 return -1; 313 challenge_response(challenge, password_hash, response); 314 return 0; 315} 316 317 318/** 319 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4 320 * @password_hash_hash: 16-octet PasswordHashHash (IN) 321 * @nt_response: 24-octet NTResponse (IN) 322 * @master_key: 16-octet MasterKey (OUT) 323 * Returns: 0 on success, -1 on failure 324 */ 325int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, 326 u8 *master_key) 327{ 328 static const u8 magic1[27] = { 329 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 330 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 331 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 332 }; 333 const unsigned char *addr[3]; 334 const size_t len[3] = { 16, 24, sizeof(magic1) }; 335 u8 hash[SHA1_MAC_LEN]; 336 337 addr[0] = password_hash_hash; 338 addr[1] = nt_response; 339 addr[2] = magic1; 340 341 if (sha1_vector(3, addr, len, hash)) 342 return -1; 343 os_memcpy(master_key, hash, 16); 344 return 0; 345} 346 347 348/** 349 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4 350 * @master_key: 16-octet MasterKey (IN) 351 * @session_key: 8-to-16 octet SessionKey (OUT) 352 * @session_key_len: SessionKeyLength (Length of session_key) (IN) 353 * @is_send: IsSend (IN, BOOLEAN) 354 * @is_server: IsServer (IN, BOOLEAN) 355 * Returns: 0 on success, -1 on failure 356 */ 357int get_asymetric_start_key(const u8 *master_key, u8 *session_key, 358 size_t session_key_len, int is_send, 359 int is_server) 360{ 361 static const u8 magic2[84] = { 362 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 363 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 364 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 365 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 366 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 367 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 368 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 369 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 370 0x6b, 0x65, 0x79, 0x2e 371 }; 372 static const u8 magic3[84] = { 373 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 374 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 375 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 376 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 377 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 378 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 379 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 380 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 381 0x6b, 0x65, 0x79, 0x2e 382 }; 383 static const u8 shs_pad1[40] = { 384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 388 }; 389 390 static const u8 shs_pad2[40] = { 391 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 392 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 393 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 394 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 395 }; 396 u8 digest[SHA1_MAC_LEN]; 397 const unsigned char *addr[4]; 398 const size_t len[4] = { 16, 40, 84, 40 }; 399 400 addr[0] = master_key; 401 addr[1] = shs_pad1; 402 if (is_send) { 403 addr[2] = is_server ? magic3 : magic2; 404 } else { 405 addr[2] = is_server ? magic2 : magic3; 406 } 407 addr[3] = shs_pad2; 408 409 if (sha1_vector(4, addr, len, digest)) 410 return -1; 411 412 if (session_key_len > SHA1_MAC_LEN) 413 session_key_len = SHA1_MAC_LEN; 414 os_memcpy(session_key, digest, session_key_len); 415 return 0; 416} 417 418 419#define PWBLOCK_LEN 516 420 421/** 422 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 423 * @password: 0-to-256-unicode-char Password (IN; UTF-8) 424 * @password_len: Length of password 425 * @password_hash: 16-octet PasswordHash (IN) 426 * @pw_block: 516-byte PwBlock (OUT) 427 * Returns: 0 on success, -1 on failure 428 */ 429int encrypt_pw_block_with_password_hash( 430 const u8 *password, size_t password_len, 431 const u8 *password_hash, u8 *pw_block) 432{ 433 size_t ucs2_len, offset; 434 u8 *pos; 435 436 os_memset(pw_block, 0, PWBLOCK_LEN); 437 438 if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0) 439 return -1; 440 441 if (ucs2_len > 256) 442 return -1; 443 444 offset = (256 - ucs2_len) * 2; 445 if (offset != 0) { 446 os_memmove(pw_block + offset, pw_block, ucs2_len * 2); 447 if (os_get_random(pw_block, offset) < 0) 448 return -1; 449 } 450 /* 451 * PasswordLength is 4 octets, but since the maximum password length is 452 * 256, only first two (in little endian byte order) can be non-zero. 453 */ 454 pos = &pw_block[2 * 256]; 455 WPA_PUT_LE16(pos, password_len * 2); 456 rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); 457 return 0; 458} 459 460 461/** 462 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 463 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8) 464 * @new_password_len: Length of new_password 465 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8) 466 * @old_password_len: Length of old_password 467 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) 468 * Returns: 0 on success, -1 on failure 469 */ 470int new_password_encrypted_with_old_nt_password_hash( 471 const u8 *new_password, size_t new_password_len, 472 const u8 *old_password, size_t old_password_len, 473 u8 *encrypted_pw_block) 474{ 475 u8 password_hash[16]; 476 477 if (nt_password_hash(old_password, old_password_len, password_hash)) 478 return -1; 479 if (encrypt_pw_block_with_password_hash(new_password, new_password_len, 480 password_hash, 481 encrypted_pw_block)) 482 return -1; 483 return 0; 484} 485 486 487/** 488 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13 489 * @password_hash: 16-octer PasswordHash (IN) 490 * @block: 16-octet Block (IN) 491 * @cypher: 16-octer Cypher (OUT) 492 */ 493void nt_password_hash_encrypted_with_block(const u8 *password_hash, 494 const u8 *block, u8 *cypher) 495{ 496 des_encrypt(password_hash, block, cypher); 497 des_encrypt(password_hash + 8, block + 7, cypher + 8); 498} 499 500 501/** 502 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 503 * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8) 504 * @new_password_len: Length of new_password 505 * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8) 506 * @old_password_len: Length of old_password 507 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) 508 * Returns: 0 on success, -1 on failure 509 */ 510int old_nt_password_hash_encrypted_with_new_nt_password_hash( 511 const u8 *new_password, size_t new_password_len, 512 const u8 *old_password, size_t old_password_len, 513 u8 *encrypted_password_hash) 514{ 515 u8 old_password_hash[16], new_password_hash[16]; 516 517 if (nt_password_hash(old_password, old_password_len, 518 old_password_hash) || 519 nt_password_hash(new_password, new_password_len, 520 new_password_hash)) 521 return -1; 522 nt_password_hash_encrypted_with_block(old_password_hash, 523 new_password_hash, 524 encrypted_password_hash); 525 return 0; 526} 527