1 /* 2 * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 3 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "sha1.h" 19 #include "ms_funcs.h" 20 #include "crypto.h" 21 22 23 /** 24 * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2 25 * @peer_challenge: 16-octet PeerChallenge (IN) 26 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 27 * @username: 0-to-256-char UserName (IN) 28 * @username_len: Length of username 29 * @challenge: 8-octet Challenge (OUT) 30 * Returns: 0 on success, -1 on failure 31 */ 32 static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, 33 const u8 *username, size_t username_len, 34 u8 *challenge) 35 { 36 u8 hash[SHA1_MAC_LEN]; 37 const unsigned char *addr[3]; 38 size_t len[3]; 39 40 addr[0] = peer_challenge; 41 len[0] = 16; 42 addr[1] = auth_challenge; 43 len[1] = 16; 44 addr[2] = username; 45 len[2] = username_len; 46 47 if (sha1_vector(3, addr, len, hash)) 48 return -1; 49 os_memcpy(challenge, hash, 8); 50 return 0; 51 } 52 53 54 /** 55 * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 56 * @password: 0-to-256-unicode-char Password (IN; ASCII) 57 * @password_len: Length of password 58 * @password_hash: 16-octet PasswordHash (OUT) 59 * Returns: 0 on success, -1 on failure 60 */ 61 int nt_password_hash(const u8 *password, size_t password_len, 62 u8 *password_hash) 63 { 64 u8 buf[512], *pos; 65 size_t i, len; 66 67 if (password_len > 256) 68 password_len = 256; 69 70 /* Convert password into unicode */ 71 for (i = 0; i < password_len; i++) { 72 buf[2 * i] = password[i]; 73 buf[2 * i + 1] = 0; 74 } 75 76 len = password_len * 2; 77 pos = buf; 78 return md4_vector(1, (const u8 **) &pos, &len, password_hash); 79 } 80 81 82 /** 83 * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 84 * @password_hash: 16-octet PasswordHash (IN) 85 * @password_hash_hash: 16-octet PasswordHashHash (OUT) 86 * Returns: 0 on success, -1 on failure 87 */ 88 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) 89 { 90 size_t len = 16; 91 return md4_vector(1, &password_hash, &len, password_hash_hash); 92 } 93 94 95 /** 96 * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5 97 * @challenge: 8-octet Challenge (IN) 98 * @password_hash: 16-octet PasswordHash (IN) 99 * @response: 24-octet Response (OUT) 100 */ 101 void challenge_response(const u8 *challenge, const u8 *password_hash, 102 u8 *response) 103 { 104 u8 zpwd[7]; 105 des_encrypt(challenge, password_hash, response); 106 des_encrypt(challenge, password_hash + 7, response + 8); 107 zpwd[0] = password_hash[14]; 108 zpwd[1] = password_hash[15]; 109 os_memset(zpwd + 2, 0, 5); 110 des_encrypt(challenge, zpwd, response + 16); 111 } 112 113 114 /** 115 * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 116 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 117 * @peer_challenge: 16-octet PeerChallenge (IN) 118 * @username: 0-to-256-char UserName (IN) 119 * @username_len: Length of username 120 * @password: 0-to-256-unicode-char Password (IN; ASCII) 121 * @password_len: Length of password 122 * @response: 24-octet Response (OUT) 123 * Returns: 0 on success, -1 on failure 124 */ 125 int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, 126 const u8 *username, size_t username_len, 127 const u8 *password, size_t password_len, 128 u8 *response) 129 { 130 u8 challenge[8]; 131 u8 password_hash[16]; 132 133 challenge_hash(peer_challenge, auth_challenge, username, username_len, 134 challenge); 135 if (nt_password_hash(password, password_len, password_hash)) 136 return -1; 137 challenge_response(challenge, password_hash, response); 138 return 0; 139 } 140 141 142 /** 143 * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1 144 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 145 * @peer_challenge: 16-octet PeerChallenge (IN) 146 * @username: 0-to-256-char UserName (IN) 147 * @username_len: Length of username 148 * @password_hash: 16-octet PasswordHash (IN) 149 * @response: 24-octet Response (OUT) 150 * Returns: 0 on success, -1 on failure 151 */ 152 int generate_nt_response_pwhash(const u8 *auth_challenge, 153 const u8 *peer_challenge, 154 const u8 *username, size_t username_len, 155 const u8 *password_hash, 156 u8 *response) 157 { 158 u8 challenge[8]; 159 160 if (challenge_hash(peer_challenge, auth_challenge, 161 username, username_len, 162 challenge)) 163 return -1; 164 challenge_response(challenge, password_hash, response); 165 return 0; 166 } 167 168 169 /** 170 * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 171 * @password_hash: 16-octet PasswordHash (IN) 172 * @nt_response: 24-octet NT-Response (IN) 173 * @peer_challenge: 16-octet PeerChallenge (IN) 174 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 175 * @username: 0-to-256-char UserName (IN) 176 * @username_len: Length of username 177 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually 178 * encoded as a 42-octet ASCII string (S=hexdump_of_response) 179 * Returns: 0 on success, -1 on failure 180 */ 181 int generate_authenticator_response_pwhash( 182 const u8 *password_hash, 183 const u8 *peer_challenge, const u8 *auth_challenge, 184 const u8 *username, size_t username_len, 185 const u8 *nt_response, u8 *response) 186 { 187 static const u8 magic1[39] = { 188 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 189 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 190 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 191 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 192 }; 193 static const u8 magic2[41] = { 194 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 195 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 196 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 197 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 198 0x6E 199 }; 200 201 u8 password_hash_hash[16], challenge[8]; 202 const unsigned char *addr1[3]; 203 const size_t len1[3] = { 16, 24, sizeof(magic1) }; 204 const unsigned char *addr2[3]; 205 const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; 206 207 addr1[0] = password_hash_hash; 208 addr1[1] = nt_response; 209 addr1[2] = magic1; 210 211 addr2[0] = response; 212 addr2[1] = challenge; 213 addr2[2] = magic2; 214 215 if (hash_nt_password_hash(password_hash, password_hash_hash)) 216 return -1; 217 if (sha1_vector(3, addr1, len1, response)) 218 return -1; 219 220 challenge_hash(peer_challenge, auth_challenge, username, username_len, 221 challenge); 222 return sha1_vector(3, addr2, len2, response); 223 } 224 225 226 /** 227 * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 228 * @password: 0-to-256-unicode-char Password (IN; ASCII) 229 * @password_len: Length of password 230 * @nt_response: 24-octet NT-Response (IN) 231 * @peer_challenge: 16-octet PeerChallenge (IN) 232 * @auth_challenge: 16-octet AuthenticatorChallenge (IN) 233 * @username: 0-to-256-char UserName (IN) 234 * @username_len: Length of username 235 * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually 236 * encoded as a 42-octet ASCII string (S=hexdump_of_response) 237 * Returns: 0 on success, -1 on failure 238 */ 239 int generate_authenticator_response(const u8 *password, size_t password_len, 240 const u8 *peer_challenge, 241 const u8 *auth_challenge, 242 const u8 *username, size_t username_len, 243 const u8 *nt_response, u8 *response) 244 { 245 u8 password_hash[16]; 246 if (nt_password_hash(password, password_len, password_hash)) 247 return -1; 248 return generate_authenticator_response_pwhash( 249 password_hash, peer_challenge, auth_challenge, 250 username, username_len, nt_response, response); 251 } 252 253 254 /** 255 * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 256 * @challenge: 8-octet Challenge (IN) 257 * @password: 0-to-256-unicode-char Password (IN; ASCII) 258 * @password_len: Length of password 259 * @response: 24-octet Response (OUT) 260 * Returns: 0 on success, -1 on failure 261 */ 262 int nt_challenge_response(const u8 *challenge, const u8 *password, 263 size_t password_len, u8 *response) 264 { 265 u8 password_hash[16]; 266 if (nt_password_hash(password, password_len, password_hash)) 267 return -1; 268 challenge_response(challenge, password_hash, response); 269 return 0; 270 } 271 272 273 /** 274 * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4 275 * @password_hash_hash: 16-octet PasswordHashHash (IN) 276 * @nt_response: 24-octet NTResponse (IN) 277 * @master_key: 16-octet MasterKey (OUT) 278 * Returns: 0 on success, -1 on failure 279 */ 280 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, 281 u8 *master_key) 282 { 283 static const u8 magic1[27] = { 284 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 285 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 286 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 287 }; 288 const unsigned char *addr[3]; 289 const size_t len[3] = { 16, 24, sizeof(magic1) }; 290 u8 hash[SHA1_MAC_LEN]; 291 292 addr[0] = password_hash_hash; 293 addr[1] = nt_response; 294 addr[2] = magic1; 295 296 if (sha1_vector(3, addr, len, hash)) 297 return -1; 298 os_memcpy(master_key, hash, 16); 299 return 0; 300 } 301 302 303 /** 304 * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4 305 * @master_key: 16-octet MasterKey (IN) 306 * @session_key: 8-to-16 octet SessionKey (OUT) 307 * @session_key_len: SessionKeyLength (Length of session_key) (IN) 308 * @is_send: IsSend (IN, BOOLEAN) 309 * @is_server: IsServer (IN, BOOLEAN) 310 * Returns: 0 on success, -1 on failure 311 */ 312 int get_asymetric_start_key(const u8 *master_key, u8 *session_key, 313 size_t session_key_len, int is_send, 314 int is_server) 315 { 316 static const u8 magic2[84] = { 317 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 318 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 319 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 320 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 321 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 322 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 323 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 324 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 325 0x6b, 0x65, 0x79, 0x2e 326 }; 327 static const u8 magic3[84] = { 328 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 329 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 330 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 331 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 332 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 333 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 334 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 335 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 336 0x6b, 0x65, 0x79, 0x2e 337 }; 338 static const u8 shs_pad1[40] = { 339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 343 }; 344 345 static const u8 shs_pad2[40] = { 346 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 347 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 348 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 349 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 350 }; 351 u8 digest[SHA1_MAC_LEN]; 352 const unsigned char *addr[4]; 353 const size_t len[4] = { 16, 40, 84, 40 }; 354 355 addr[0] = master_key; 356 addr[1] = shs_pad1; 357 if (is_send) { 358 addr[2] = is_server ? magic3 : magic2; 359 } else { 360 addr[2] = is_server ? magic2 : magic3; 361 } 362 addr[3] = shs_pad2; 363 364 if (sha1_vector(4, addr, len, digest)) 365 return -1; 366 367 if (session_key_len > SHA1_MAC_LEN) 368 session_key_len = SHA1_MAC_LEN; 369 os_memcpy(session_key, digest, session_key_len); 370 return 0; 371 } 372 373 374 #define PWBLOCK_LEN 516 375 376 /** 377 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 378 * @password: 0-to-256-unicode-char Password (IN; ASCII) 379 * @password_len: Length of password 380 * @password_hash: 16-octet PasswordHash (IN) 381 * @pw_block: 516-byte PwBlock (OUT) 382 * Returns: 0 on success, -1 on failure 383 */ 384 int encrypt_pw_block_with_password_hash( 385 const u8 *password, size_t password_len, 386 const u8 *password_hash, u8 *pw_block) 387 { 388 size_t i, offset; 389 u8 *pos; 390 391 if (password_len > 256) 392 return -1; 393 394 os_memset(pw_block, 0, PWBLOCK_LEN); 395 offset = (256 - password_len) * 2; 396 if (os_get_random(pw_block, offset) < 0) 397 return -1; 398 for (i = 0; i < password_len; i++) 399 pw_block[offset + i * 2] = password[i]; 400 /* 401 * PasswordLength is 4 octets, but since the maximum password length is 402 * 256, only first two (in little endian byte order) can be non-zero. 403 */ 404 pos = &pw_block[2 * 256]; 405 WPA_PUT_LE16(pos, password_len * 2); 406 rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); 407 return 0; 408 } 409 410 411 /** 412 * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 413 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) 414 * @new_password_len: Length of new_password 415 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) 416 * @old_password_len: Length of old_password 417 * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) 418 * Returns: 0 on success, -1 on failure 419 */ 420 int new_password_encrypted_with_old_nt_password_hash( 421 const u8 *new_password, size_t new_password_len, 422 const u8 *old_password, size_t old_password_len, 423 u8 *encrypted_pw_block) 424 { 425 u8 password_hash[16]; 426 427 if (nt_password_hash(old_password, old_password_len, password_hash)) 428 return -1; 429 if (encrypt_pw_block_with_password_hash(new_password, new_password_len, 430 password_hash, 431 encrypted_pw_block)) 432 return -1; 433 return 0; 434 } 435 436 437 /** 438 * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13 439 * @password_hash: 16-octer PasswordHash (IN) 440 * @block: 16-octet Block (IN) 441 * @cypher: 16-octer Cypher (OUT) 442 */ 443 void nt_password_hash_encrypted_with_block(const u8 *password_hash, 444 const u8 *block, u8 *cypher) 445 { 446 des_encrypt(password_hash, block, cypher); 447 des_encrypt(password_hash + 8, block + 7, cypher + 8); 448 } 449 450 451 /** 452 * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 453 * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) 454 * @new_password_len: Length of new_password 455 * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) 456 * @old_password_len: Length of old_password 457 * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) 458 * Returns: 0 on success, -1 on failure 459 */ 460 int old_nt_password_hash_encrypted_with_new_nt_password_hash( 461 const u8 *new_password, size_t new_password_len, 462 const u8 *old_password, size_t old_password_len, 463 u8 *encrypted_password_hash) 464 { 465 u8 old_password_hash[16], new_password_hash[16]; 466 467 if (nt_password_hash(old_password, old_password_len, 468 old_password_hash) || 469 nt_password_hash(new_password, new_password_len, 470 new_password_hash)) 471 return -1; 472 nt_password_hash_encrypted_with_block(old_password_hash, 473 new_password_hash, 474 encrypted_password_hash); 475 return 0; 476 } 477