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