1/* 2 * Copyright (c) 2001-2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <unistd.h> 25#include <stdlib.h> 26#include <stdio.h> 27#include <string.h> 28#include <sys/types.h> 29#include <CommonCrypto/CommonDigest.h> 30#include <CommonCrypto/CommonCryptor.h> 31#include <libkern/OSByteOrder.h> 32#include <stdbool.h> 33#include "mschap.h" 34 35#include "DESSupport.h" 36 37static void 38ChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 39 const uint8_t password_hash[NT_PASSWORD_HASH_SIZE], 40 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]); 41 42static void 43password_to_unicode(const uint8_t * password, uint32_t password_len, 44 uint8_t * unicode_password) 45{ 46 int i; 47 48 if (password_len > NT_MAXPWLEN) { 49 password_len = NT_MAXPWLEN; 50 } 51 bzero(unicode_password, password_len * 2); 52 for (i = 0; i < password_len; i++) { 53 unicode_password[i * 2] = password[i]; 54 } 55 return; 56} 57 58static void 59NTPasswordHash(const uint8_t * password, uint32_t password_len, 60 uint8_t hash[NT_PASSWORD_HASH_SIZE]) 61{ 62 CC_MD4(password, password_len, hash); 63 return; 64} 65 66static void 67NTPasswordHashHash(const uint8_t * password, uint32_t password_len, 68 uint8_t ret_hash[NT_PASSWORD_HASH_SIZE]) 69{ 70 uint8_t hash[NT_PASSWORD_HASH_SIZE]; 71 72 NTPasswordHash(password, password_len, hash); 73 NTPasswordHash(hash, NT_PASSWORD_HASH_SIZE, ret_hash); 74 return; 75} 76 77static void 78NTChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 79 const uint8_t * password, uint32_t password_len, 80 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]) 81{ 82 uint8_t hash[NT_PASSWORD_HASH_SIZE]; 83 84 NTPasswordHash(password, password_len, hash); 85 ChallengeResponse(challenge, hash, response); 86 return; 87} 88 89static void 90NTMPPEChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 91 const uint8_t * password, 92 uint32_t password_len, 93 uint8_t response[MSCHAP_NT_CHALLENGE_SIZE]) 94{ 95 uint8_t hash[NT_PASSWORD_HASH_SIZE]; 96 97 NTPasswordHashHash(password, password_len, hash); 98 ChallengeResponse(challenge, hash, response); 99 return; 100} 101 102static void 103ChallengeResponse(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 104 const uint8_t password_hash[NT_PASSWORD_HASH_SIZE], 105 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]) 106{ 107 uint8_t zhash[21]; 108 109 /* zero pad the password hash to 21 bytes */ 110 bzero(zhash, 21); 111 bcopy(password_hash, zhash, NT_PASSWORD_HASH_SIZE); 112 113 DesEncrypt(challenge, zhash, response); 114 DesEncrypt(challenge, zhash + 7, response + 8); 115 DesEncrypt(challenge, zhash + 14, response + 16); 116 return; 117} 118 119static void 120ChallengeHash(const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE], 121 const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE], 122 const uint8_t * username, 123 uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE]) 124{ 125 const uint8_t * user; 126 CC_SHA1_CTX context; 127 uint8_t hash[CC_SHA1_DIGEST_LENGTH]; 128 129 /* find the last backslash to get the user name to use for the hash */ 130 user = (const uint8_t *)strrchr((const char *)username, '\\'); 131 if (user == NULL) { 132 user = username; 133 } 134 else { 135 user = user + 1; 136 } 137 CC_SHA1_Init(&context); 138 CC_SHA1_Update(&context, peer_challenge, MSCHAP2_CHALLENGE_SIZE); 139 CC_SHA1_Update(&context, auth_challenge, MSCHAP2_CHALLENGE_SIZE); 140 CC_SHA1_Update(&context, user, (int)strlen((const char *)user)); 141 CC_SHA1_Final(hash, &context); 142 bcopy(hash, challenge, MSCHAP_NT_CHALLENGE_SIZE); 143 return; 144} 145 146 147 148static const uint8_t magic1[39] = { 149 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 150 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 151 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 152 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; 153 154static const uint8_t magic2[41] = { 155 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 156 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 157 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 158 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 159 0x6E}; 160 161static void 162GenerateAuthResponse(uint8_t * password, uint32_t password_len, 163 const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE], 164 const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE], 165 const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE], 166 const uint8_t * username, 167 uint8_t auth_response[MSCHAP2_AUTH_RESPONSE_SIZE]) 168{ 169 uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE]; 170 CC_SHA1_CTX context; 171 int i; 172 uint8_t hash[CC_SHA1_DIGEST_LENGTH]; 173 uint8_t password_hash[NT_PASSWORD_HASH_SIZE]; 174 uint8_t * scan; 175 176 NTPasswordHashHash(password, password_len, password_hash); 177 178 CC_SHA1_Init(&context); 179 CC_SHA1_Update(&context, password_hash, NT_PASSWORD_HASH_SIZE); 180 CC_SHA1_Update(&context, nt_response, MSCHAP_NT_RESPONSE_SIZE); 181 CC_SHA1_Update(&context, magic1, 39); 182 CC_SHA1_Final(hash, &context); 183 184 ChallengeHash(peer_challenge, auth_challenge, username, 185 challenge); 186 187 CC_SHA1_Init(&context); 188 CC_SHA1_Update(&context, hash, CC_SHA1_DIGEST_LENGTH); 189 CC_SHA1_Update(&context, challenge, MSCHAP_NT_CHALLENGE_SIZE); 190 CC_SHA1_Update(&context, magic2, 41); 191 CC_SHA1_Final(hash, &context); 192 193 /* 194 * Encode the value of 'hash' as "S=" followed by 195 * 40 ASCII hexadecimal digits and return it in 196 * 'auth_response'. 197 * For example, 198 * "S=0123456789ABCDEF0123456789ABCDEF01234567" 199 */ 200 auth_response[0] = 'S'; 201 auth_response[1] = '='; 202 for (i = 0, scan = auth_response + 2; 203 i < CC_SHA1_DIGEST_LENGTH; i++, scan +=2) { 204 char hexstr[3]; 205 snprintf(hexstr, 3, "%02X", hash[i]); 206 scan[0] = hexstr[0]; 207 scan[1] = hexstr[1]; 208 } 209 return; 210} 211 212/* 213 * Exported Functions 214 */ 215 216#define HASH_INPUT_SIZE (NT_PASSWORD_HASH_SIZE + (MSCHAP_NT_CHALLENGE_SIZE + MSCHAP_NT_RESPONSE_SIZE) * 2) 217 218void 219NTSessionKey16(const uint8_t * password, uint32_t password_len, 220 const uint8_t client_challenge[MSCHAP_NT_CHALLENGE_SIZE], 221 const uint8_t server_response[MSCHAP_NT_RESPONSE_SIZE], 222 const uint8_t server_challenge[MSCHAP_NT_CHALLENGE_SIZE], 223 uint8_t key[NT_SESSION_KEY_SIZE]) 224{ 225 uint8_t input[HASH_INPUT_SIZE]; 226 int offset; 227 uint8_t unicode_password[NT_MAXPWLEN * 2]; 228 229 /* add hash of the hash of the unicode password */ 230 offset = 0; 231 password_to_unicode(password, password_len, unicode_password); 232 NTPasswordHashHash(unicode_password, password_len * 2, input); 233 offset += NT_PASSWORD_HASH_SIZE; 234 235 /* add the client challenge */ 236 bcopy(client_challenge, input + offset, MSCHAP_NT_CHALLENGE_SIZE); 237 offset += MSCHAP_NT_CHALLENGE_SIZE; 238 239 /* add the server response */ 240 bcopy(server_response, input + offset, MSCHAP_NT_RESPONSE_SIZE); 241 offset += MSCHAP_NT_RESPONSE_SIZE; 242 243 /* add the server challenge */ 244 bcopy(server_challenge, input + offset, MSCHAP_NT_CHALLENGE_SIZE); 245 offset += MSCHAP_NT_CHALLENGE_SIZE; 246 247 /* compute the client response */ 248 NTChallengeResponse(server_challenge, unicode_password, 249 password_len * 2, input + offset); 250 251 CC_MD5(input, HASH_INPUT_SIZE, key); 252 return; 253} 254 255void 256MSChap(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 257 const uint8_t * password, uint32_t password_len, 258 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]) 259{ 260 uint8_t unicode_password[NT_MAXPWLEN * 2]; 261 262 password_to_unicode(password, password_len, unicode_password); 263 NTChallengeResponse(challenge, unicode_password, password_len * 2, 264 response); 265 return; 266} 267 268void 269MSChap_MPPE(const uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE], 270 const uint8_t * password, uint32_t password_len, 271 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]) 272{ 273 uint8_t unicode_password[NT_MAXPWLEN * 2]; 274 275 password_to_unicode(password, password_len, unicode_password); 276 NTMPPEChallengeResponse(challenge, unicode_password, 277 password_len * 2, response); 278 return; 279} 280 281void 282MSChap2(const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE], 283 const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE], 284 const uint8_t * username, 285 const uint8_t * password, uint32_t password_len, 286 uint8_t response[MSCHAP_NT_RESPONSE_SIZE]) 287{ 288 uint8_t unicode_password[NT_MAXPWLEN * 2]; 289 uint8_t challenge[MSCHAP_NT_CHALLENGE_SIZE]; 290 291 ChallengeHash(peer_challenge, auth_challenge, username, 292 challenge); 293 password_to_unicode(password, password_len, unicode_password); 294 NTChallengeResponse(challenge, unicode_password, password_len * 2, 295 response); 296 return; 297} 298 299bool 300MSChap2AuthResponseValid(const uint8_t * password, uint32_t password_len, 301 const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE], 302 const uint8_t peer_challenge[MSCHAP2_CHALLENGE_SIZE], 303 const uint8_t auth_challenge[MSCHAP2_CHALLENGE_SIZE], 304 const uint8_t * username, 305 const uint8_t response[MSCHAP2_AUTH_RESPONSE_SIZE]) 306{ 307 uint8_t my_response[MSCHAP2_AUTH_RESPONSE_SIZE]; 308 uint8_t unicode_password[NT_MAXPWLEN * 2]; 309 310 password_to_unicode(password, password_len, unicode_password); 311 312 GenerateAuthResponse(unicode_password, password_len * 2, 313 nt_response, 314 peer_challenge, 315 auth_challenge, 316 username, 317 my_response); 318 if (bcmp(my_response, response, MSCHAP2_AUTH_RESPONSE_SIZE)) { 319 return (false); 320 } 321 return (true); 322} 323 324static void 325rc4_encrypt(const void * clear, uint32_t clear_length, 326 const void * key, uint32_t key_length, 327 void * cypher) 328{ 329 size_t bytes_processed; 330 CCCryptorStatus status; 331 332 /* sizeof(cypher) == clear_length */ 333 status = CCCrypt(kCCEncrypt, kCCAlgorithmRC4, 0, 334 key, key_length, NULL, 335 clear, clear_length, 336 cypher, clear_length, 337 &bytes_processed); 338 if (status != kCCSuccess) { 339 fprintf(stderr, "rc4_encrypt: CCCrypt failed with %d\n", 340 status); 341 return; 342 } 343 return; 344} 345 346static void 347EncryptPwBlockWithPasswordHash(const uint8_t * password, 348 uint32_t password_len, 349 const uint8_t pw_hash[NT_PASSWORD_HASH_SIZE], 350 NTPasswordBlockRef pwblock) 351{ 352 NTPasswordBlock clear_pwblock; 353 int offset; 354 uint32_t password_len_little_endian; 355 356 MSChapFillWithRandom(&clear_pwblock, sizeof(clear_pwblock)); 357 offset = sizeof(clear_pwblock.password) - password_len; 358 bcopy(password, ((void *)&clear_pwblock) + offset, password_len); 359 /* convert password length to little endian */ 360 password_len_little_endian = OSSwapHostToLittleInt32(password_len); 361 bcopy(&password_len_little_endian, clear_pwblock.password_length, 362 sizeof(uint32_t)); 363 rc4_encrypt(&clear_pwblock, sizeof(clear_pwblock), 364 pw_hash, NT_PASSWORD_HASH_SIZE, pwblock); 365 return; 366} 367 368/* 369 * RFC 2759, Section 8.9 370 * NewPasswordEncryptedWithOldNtPasswordHash 371 */ 372void 373NTPasswordBlockEncryptNewPasswordWithOldHash(const uint8_t * new_password, 374 uint32_t new_password_len, 375 const uint8_t * old_password, 376 uint32_t old_password_len, 377 NTPasswordBlockRef pwblock) 378{ 379 uint8_t hash[NT_PASSWORD_HASH_SIZE]; 380 uint8_t new_password_unicode[NT_MAXPWLEN * 2]; 381 uint8_t old_password_unicode[NT_MAXPWLEN * 2]; 382 383 password_to_unicode(new_password, new_password_len, new_password_unicode); 384 password_to_unicode(old_password, old_password_len, old_password_unicode); 385 386 NTPasswordHash(old_password_unicode, old_password_len * 2, hash); 387 EncryptPwBlockWithPasswordHash(new_password_unicode, 388 new_password_len * 2, 389 hash, pwblock); 390 return; 391} 392 393/* 394 * NtPasswordHashEncryptedWithBlock() 395 */ 396static void 397NTPasswordHashEncryptedWithBlock(const uint8_t pw_hash[NT_PASSWORD_HASH_SIZE], 398 const uint8_t block[NT_PASSWORD_HASH_SIZE], 399 uint8_t cypher[NT_PASSWORD_HASH_SIZE]) 400{ 401 DesEncrypt(pw_hash, block, cypher); 402 DesEncrypt(pw_hash + 8, block + 7, cypher + 8); 403 return; 404} 405 406 407/* 408 * RFC 2759, Section 8.12 409 * OldNtPasswordHashEncryptedWithNewNtPasswordHash() 410 */ 411void 412NTPasswordHashEncryptOldWithNew(const uint8_t * new_password, 413 uint32_t new_password_len, 414 const uint8_t * old_password, 415 uint32_t old_password_len, 416 uint8_t encrypted_hash[NT_PASSWORD_HASH_SIZE]) 417{ 418 uint8_t new_password_unicode[NT_MAXPWLEN * 2]; 419 uint8_t new_pw_hash[NT_PASSWORD_HASH_SIZE]; 420 uint8_t old_password_unicode[NT_MAXPWLEN * 2]; 421 uint8_t old_pw_hash[NT_PASSWORD_HASH_SIZE]; 422 423 password_to_unicode(new_password, new_password_len, new_password_unicode); 424 NTPasswordHash(new_password_unicode, new_password_len * 2, new_pw_hash); 425 426 password_to_unicode(old_password, old_password_len, old_password_unicode); 427 NTPasswordHash(old_password_unicode, old_password_len * 2, old_pw_hash); 428 429 NTPasswordHashEncryptedWithBlock(old_pw_hash, new_pw_hash, 430 encrypted_hash); 431 return; 432} 433 434void 435MSChapFillWithRandom(void * buf, uint32_t len) 436{ 437 int i; 438 int n; 439 u_int32_t * p = (u_int32_t *)buf; 440 441 n = len / sizeof(*p); 442 for (i = 0; i < n; i++, p++) { 443 *p = arc4random(); 444 } 445 return; 446} 447 448/** 449 ** RFC 3079 450 ** MPPE functions 451 **/ 452 453/* 454 * Pads used in key derivation 455 */ 456 457const static uint8_t SHSpad1[40] = 458 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 462 463const static uint8_t SHSpad2[40] = 464 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 465 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 466 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 467 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; 468 469/* 470 * "Magic" constants used in key derivations 471 */ 472 473const static uint8_t Magic1[27] = 474 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 475 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 476 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; 477 478#define MAGIC2_3_SIZE 84 479#define MAGIC2_SIZE MAGIC2_3_SIZE 480#define MAGIC3_SIZE MAGIC2_3_SIZE 481 482const static uint8_t Magic2[MAGIC2_SIZE] = 483 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 484 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 485 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 486 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 487 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 488 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 489 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 490 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 491 0x6b, 0x65, 0x79, 0x2e }; 492 493const static uint8_t Magic3[MAGIC3_SIZE] = 494 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 495 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 496 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 497 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 498 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 499 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 500 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 501 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 502 0x6b, 0x65, 0x79, 0x2e }; 503 504static void 505GetMasterKey(const uint8_t PasswordHashHash[NT_PASSWORD_HASH_SIZE], 506 const uint8_t NTResponse[MSCHAP_NT_RESPONSE_SIZE], 507 uint8_t MasterKey[NT_MASTER_KEY_SIZE]) 508{ 509 CC_SHA1_CTX context; 510 uint8_t Digest[CC_SHA1_DIGEST_LENGTH]; 511 512 memset(Digest, 0, sizeof(Digest)); 513 514 CC_SHA1_Init(&context); 515 CC_SHA1_Update(&context, PasswordHashHash, NT_PASSWORD_HASH_SIZE); 516 CC_SHA1_Update(&context, NTResponse, MSCHAP_NT_RESPONSE_SIZE); 517 CC_SHA1_Update(&context, Magic1, sizeof(Magic1)); 518 CC_SHA1_Final(Digest, &context); 519 memcpy(MasterKey, Digest, NT_MASTER_KEY_SIZE); 520 return; 521} 522 523void 524MSChap2_MPPEGetMasterKey(const uint8_t * password, uint32_t password_len, 525 const uint8_t NTResponse[MSCHAP_NT_RESPONSE_SIZE], 526 uint8_t MasterKey[NT_MASTER_KEY_SIZE]) 527{ 528 uint8_t password_hash[NT_PASSWORD_HASH_SIZE]; 529 uint8_t unicode_password[NT_MAXPWLEN * 2]; 530 531 password_to_unicode(password, password_len, unicode_password); 532 533 NTPasswordHashHash(unicode_password, password_len * 2, password_hash); 534 GetMasterKey(password_hash, NTResponse, MasterKey); 535} 536 537void 538MSChap2_MPPEGetAsymetricStartKey(const uint8_t MasterKey[NT_MASTER_KEY_SIZE], 539 uint8_t SessionKey[NT_SESSION_KEY_SIZE], 540 int SessionKeyLength, 541 bool IsSend, 542 bool IsServer) 543{ 544 CC_SHA1_CTX context; 545 uint8_t Digest[CC_SHA1_DIGEST_LENGTH]; 546 const uint8_t * s; 547 548 /* 549 * The logic in the spec says: 550 * if (IsSend) { 551 * if (IsServer) { 552 * s = Magic3; 553 * } 554 * else { 555 * s = Magic2; 556 * } 557 * } 558 * else { 559 * if (IsServer) { 560 * s = Magic2; 561 * } 562 * else { 563 * s = Magic3; 564 * } 565 * } 566 * 567 * The corresponding truth table is: 568 * IsSend IsServer s 569 * 0 0 Magic3 570 * 0 1 Magic2 571 * 1 0 Magic2 572 * 1 1 Magic3 573 * which is simply: 574 * s = (IsSend == IsServer) ? Magic3 : Magic2; 575 */ 576 s = (IsSend == IsServer) ? Magic3 : Magic2; 577 memset(Digest, 0, sizeof(Digest)); 578 CC_SHA1_Init(&context); 579 CC_SHA1_Update(&context, MasterKey, NT_MASTER_KEY_SIZE); 580 CC_SHA1_Update(&context, SHSpad1, sizeof(SHSpad1)); 581 CC_SHA1_Update(&context, s, MAGIC2_3_SIZE); 582 CC_SHA1_Update(&context, SHSpad2, sizeof(SHSpad2)); 583 CC_SHA1_Final(Digest, &context); 584 585 if (SessionKeyLength > NT_SESSION_KEY_SIZE) { 586 SessionKeyLength = NT_SESSION_KEY_SIZE; 587 } 588 memcpy(SessionKey, Digest, SessionKeyLength); 589 return; 590} 591 592#ifdef TEST_MSCHAP 593 594const char * password = "clientPass"; 595const uint8_t nt_response[MSCHAP_NT_RESPONSE_SIZE] = { 596 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E, 597 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54, 598 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF 599}; 600 601const uint8_t PasswordHashHash[NT_PASSWORD_HASH_SIZE] = { 602 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C, 603 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F 604}; 605 606const uint8_t MasterKey[NT_MASTER_KEY_SIZE] = { 607 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C, 608 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31 609}; 610 611const uint8_t SendStartKey128[NT_SESSION_KEY_SIZE] ={ 612 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B, 613 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB 614}; 615 616 617int 618main() 619{ 620 uint8_t master[NT_MASTER_KEY_SIZE]; 621 uint8_t send_start[NT_SESSION_KEY_SIZE]; 622 623 MSChap2_MPPEGetMasterKey((const uint8_t *)password, strlen(password), 624 nt_response, master); 625 if (bcmp(master, MasterKey, NT_MASTER_KEY_SIZE) != 0) { 626 printf("Master Key generation failed\n"); 627 exit(1); 628 } 629 printf("Master Key generation successful\n"); 630 631 MSChap2_MPPEGetAsymetricStartKey(master, 632 send_start, sizeof(send_start), 633 1, 1); 634 if (bcmp(send_start, SendStartKey128, sizeof(send_start)) != 0) { 635 printf("SendStartKey128 generation failed\n"); 636 exit(1); 637 } 638 printf("SendStartKey128 generation successful\n"); 639 exit(0); 640 return (0); 641} 642#endif /* TEST_MSCHAP */ 643