1 /* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $ 33 */ 34 35 /* 36 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 37 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 38 */ 39 40 /* 41 * NTLM support functions 42 * 43 * Some code from the driver: smb_smb.c, smb_crypt.c 44 */ 45 46 #include <sys/errno.h> 47 #include <sys/types.h> 48 #include <sys/md4.h> 49 #include <sys/md5.h> 50 51 #include <ctype.h> 52 #include <stdlib.h> 53 #include <strings.h> 54 55 #include <netsmb/smb_lib.h> 56 57 #include "private.h" 58 #include "charsets.h" 59 #include "smb_crypt.h" 60 #include "ntlm.h" 61 62 63 /* 64 * ntlm_compute_lm_hash 65 * 66 * Given a password, compute the LM hash. 67 * a.k.a. ResponseKeyLM in [MS-NLMP] 68 * 69 * Output: 70 * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash) 71 * Inputs: 72 * ucpw: User's password, upper-case UTF-8 string. 73 * 74 * Source: Implementing CIFS (Chris Hertel) 75 * 76 * P14 = UCPW padded to 14-bytes, or truncated (as needed) 77 * result = Encrypt(Key=P14, Data=MagicString) 78 */ 79 int 80 ntlm_compute_lm_hash(uchar_t *hash, const char *pass) 81 { 82 static const uchar_t M8[8] = "KGS!@#$%"; 83 uchar_t P14[14 + 1]; 84 int err; 85 char *ucpw; 86 87 /* First, convert the p/w to upper case. */ 88 ucpw = utf8_str_toupper(pass); 89 if (ucpw == NULL) 90 return (ENOMEM); 91 92 /* Pad or truncate the upper-case P/W as needed. */ 93 bzero(P14, sizeof (P14)); 94 (void) strncpy((char *)P14, ucpw, 14); 95 96 /* Compute the hash. */ 97 err = smb_encrypt_DES(hash, NTLM_HASH_SZ, 98 P14, 14, M8, 8); 99 100 free(ucpw); 101 return (err); 102 } 103 104 /* 105 * ntlm_compute_nt_hash 106 * 107 * Given a password, compute the NT hash. 108 * a.k.a. the ResponseKeyNT in [MS-NLMP] 109 * 110 * Output: 111 * hash: 16-byte "NT" hash (normally ctx->ct_nthash) 112 * Inputs: 113 * upw: User's password, mixed-case UCS-2LE. 114 * pwlen: Size (in bytes) of upw 115 */ 116 int 117 ntlm_compute_nt_hash(uchar_t *hash, const char *pass) 118 { 119 MD4_CTX ctx; 120 uint16_t *unipw = NULL; 121 int pwsz; 122 123 /* First, convert the password to unicode. */ 124 unipw = convert_utf8_to_leunicode(pass); 125 if (unipw == NULL) 126 return (ENOMEM); 127 pwsz = unicode_strlen(unipw) << 1; 128 129 /* Compute the hash. */ 130 MD4Init(&ctx); 131 MD4Update(&ctx, unipw, pwsz); 132 MD4Final(hash, &ctx); 133 134 free(unipw); 135 return (0); 136 } 137 138 /* 139 * ntlm_v1_response 140 * a.k.a. DESL() in [MS-NLMP] 141 * 142 * Create an LM response from the given LM hash and challenge, 143 * or an NTLM repsonse from a given NTLM hash and challenge. 144 * Both response types are 24 bytes (NTLM_V1_RESP_SZ) 145 */ 146 static int 147 ntlm_v1_response(uchar_t *resp, 148 const uchar_t *hash, 149 const uchar_t *chal, int clen) 150 { 151 uchar_t S21[21]; 152 int err; 153 154 /* 155 * 14-byte LM Hash should be padded with 5 nul bytes to create 156 * a 21-byte string to be used in producing LM response 157 */ 158 bzero(&S21, sizeof (S21)); 159 bcopy(hash, S21, NTLM_HASH_SZ); 160 161 /* padded LM Hash -> LM Response */ 162 err = smb_encrypt_DES(resp, NTLM_V1_RESP_SZ, 163 S21, 21, chal, clen); 164 return (err); 165 } 166 167 /* 168 * Calculate an NTLMv1 session key (16 bytes). 169 */ 170 static void 171 ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash) 172 { 173 MD4_CTX md4; 174 175 MD4Init(&md4); 176 MD4Update(&md4, nt_hash, NTLM_HASH_SZ); 177 MD4Final(ssn_key, &md4); 178 } 179 180 /* 181 * Compute both the LM(v1) response and the NTLM(v1) response, 182 * and put them in the mbdata chains passed. This allocates 183 * mbuf chains in the output args, which the caller frees. 184 */ 185 int 186 ntlm_put_v1_responses(struct smb_ctx *ctx, 187 struct mbdata *lm_mbp, struct mbdata *nt_mbp) 188 { 189 uchar_t *lmresp, *ntresp; 190 int err; 191 192 /* Get mbuf chain for the LM response. */ 193 if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0) 194 return (err); 195 196 /* Get mbuf chain for the NT response. */ 197 if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0) 198 return (err); 199 200 /* 201 * Compute the NTLM response, derived from 202 * the challenge and the NT hash (a.k.a ResponseKeyNT) 203 */ 204 err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); 205 if (err) 206 return (err); 207 bzero(ntresp, NTLM_V1_RESP_SZ); 208 err = ntlm_v1_response(ntresp, ctx->ct_nthash, 209 ctx->ct_srv_chal, NTLM_CHAL_SZ); 210 211 /* 212 * Compute the LM response, derived from 213 * the challenge and the ASCII password. 214 * Per. [MS-NLMP 3.3.1] if NoLmResponse, 215 * send the NT response for both NT+LM. 216 */ 217 err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); 218 if (err) 219 return (err); 220 memcpy(lmresp, ntresp, NTLM_V1_RESP_SZ); 221 if (ctx->ct_authflags & SMB_AT_LM1) { 222 /* They asked to send the LM hash too. */ 223 err = ntlm_v1_response(lmresp, ctx->ct_lmhash, 224 ctx->ct_srv_chal, NTLM_CHAL_SZ); 225 if (err) 226 return (err); 227 } 228 229 /* 230 * Compute the session key 231 */ 232 ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); 233 234 return (err); 235 } 236 237 /* 238 * Compute both the LM(v1x) response and the NTLM(v1x) response, 239 * and put them in the mbdata chains passed. "v1x" here refers to 240 * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY used with NTLMSSP, 241 * also known by its shorter alias NTLMSSP_NEGOTIATE_NTLM2. 242 * [MS-NLMP 3.3.1] 243 * 244 * This allocates mbuf chains in the output args (caller frees). 245 */ 246 int 247 ntlm_put_v1x_responses(struct smb_ctx *ctx, 248 struct mbdata *lm_mbp, struct mbdata *nt_mbp) 249 { 250 MD5_CTX context; 251 uchar_t challenges[2 * NTLM_CHAL_SZ]; 252 uchar_t digest[NTLM_HASH_SZ]; 253 uchar_t *lmresp, *ntresp; 254 int err; 255 256 /* Get mbuf chain for the LM response. */ 257 if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0) 258 return (err); 259 260 /* Get mbuf chain for the NT response. */ 261 if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0) 262 return (err); 263 264 /* 265 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge) 266 */ 267 memcpy(challenges, ctx->ct_srv_chal, NTLM_CHAL_SZ); 268 memcpy(challenges + NTLM_CHAL_SZ, ctx->ct_clnonce, NTLM_CHAL_SZ); 269 270 /* 271 * digest = MD5(challenges) 272 */ 273 MD5Init(&context); 274 MD5Update(&context, challenges, sizeof (challenges)); 275 MD5Final(digest, &context); 276 277 /* 278 * Compute the NTLM response, derived from the 279 * NT hash (a.k.a ResponseKeyNT) and the first 280 * 8 bytes of the MD5 digest of the challenges. 281 */ 282 err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); 283 if (err) 284 return (err); 285 bzero(ntresp, NTLM_V1_RESP_SZ); 286 err = ntlm_v1_response(ntresp, ctx->ct_nthash, 287 digest, NTLM_CHAL_SZ); 288 289 /* 290 * With "Extended Session Security", the LM response 291 * is simply the client challenge (nonce) padded out. 292 */ 293 err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); 294 if (err) 295 return (err); 296 bzero(lmresp, NTLM_V1_RESP_SZ); 297 memcpy(lmresp, ctx->ct_clnonce, NTLM_CHAL_SZ); 298 299 /* 300 * Compute the session key 301 */ 302 ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash); 303 304 return (err); 305 } 306 307 /* 308 * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems. 309 * The HMACT64() function is the same as the HMAC-MD5() except that 310 * it truncates the input key to 64 bytes rather than hashing it down 311 * to 16 bytes using the MD5() function. 312 * 313 * Output: digest (16-bytes) 314 */ 315 static void 316 HMACT64(uchar_t *digest, 317 const uchar_t *key, size_t key_len, 318 const uchar_t *data, size_t data_len) 319 { 320 MD5_CTX context; 321 uchar_t k_ipad[64]; /* inner padding - key XORd with ipad */ 322 uchar_t k_opad[64]; /* outer padding - key XORd with opad */ 323 int i; 324 325 /* if key is longer than 64 bytes use only the first 64 bytes */ 326 if (key_len > 64) 327 key_len = 64; 328 329 /* 330 * The HMAC-MD5 (and HMACT64) transform looks like: 331 * 332 * MD5(K XOR opad, MD5(K XOR ipad, data)) 333 * 334 * where K is an n byte key 335 * ipad is the byte 0x36 repeated 64 times 336 * opad is the byte 0x5c repeated 64 times 337 * and data is the data being protected. 338 */ 339 340 /* start out by storing key in pads */ 341 bzero(k_ipad, sizeof (k_ipad)); 342 bzero(k_opad, sizeof (k_opad)); 343 bcopy(key, k_ipad, key_len); 344 bcopy(key, k_opad, key_len); 345 346 /* XOR key with ipad and opad values */ 347 for (i = 0; i < 64; i++) { 348 k_ipad[i] ^= 0x36; 349 k_opad[i] ^= 0x5c; 350 } 351 352 /* 353 * perform inner MD5 354 */ 355 MD5Init(&context); /* init context for 1st pass */ 356 MD5Update(&context, k_ipad, 64); /* start with inner pad */ 357 MD5Update(&context, data, data_len); /* then data of datagram */ 358 MD5Final(digest, &context); /* finish up 1st pass */ 359 360 /* 361 * perform outer MD5 362 */ 363 MD5Init(&context); /* init context for 2nd pass */ 364 MD5Update(&context, k_opad, 64); /* start with outer pad */ 365 MD5Update(&context, digest, 16); /* then results of 1st hash */ 366 MD5Final(digest, &context); /* finish up 2nd pass */ 367 } 368 369 370 /* 371 * Compute an NTLMv2 hash given the NTLMv1 hash, the user name, 372 * and the destination (machine or domain name). 373 * 374 * Output: 375 * v2hash: 16-byte NTLMv2 hash. 376 * Inputs: 377 * v1hash: 16-byte NTLMv1 hash. 378 * user: User name, UPPER-case UTF-8 string. 379 * destination: Domain or server, MIXED-case UTF-8 string. 380 */ 381 static int 382 ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash, 383 const char *user, const char *destination) 384 { 385 int ulen, dlen; 386 size_t ucs2len; 387 uint16_t *ucs2data = NULL; 388 char *utf8data = NULL; 389 int err = ENOMEM; 390 391 /* 392 * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest)) 393 * where "dest" is the domain or server name ("target name") 394 * Note: user name is converted to upper-case by the caller. 395 */ 396 397 /* utf8data = concat(user, dest) */ 398 ulen = strlen(user); 399 dlen = strlen(destination); 400 utf8data = malloc(ulen + dlen + 1); 401 if (utf8data == NULL) 402 goto out; 403 bcopy(user, utf8data, ulen); 404 bcopy(destination, utf8data + ulen, dlen + 1); 405 406 /* Convert to UCS-2LE */ 407 ucs2data = convert_utf8_to_leunicode(utf8data); 408 if (ucs2data == NULL) 409 goto out; 410 ucs2len = 2 * unicode_strlen(ucs2data); 411 412 HMACT64(v2hash, v1hash, NTLM_HASH_SZ, 413 (uchar_t *)ucs2data, ucs2len); 414 err = 0; 415 out: 416 if (ucs2data) 417 free(ucs2data); 418 if (utf8data) 419 free(utf8data); 420 return (err); 421 } 422 423 /* 424 * Compute a partial LMv2 or NTLMv2 response (first 16-bytes). 425 * The full response is composed by the caller by 426 * appending the client_data to the returned hash. 427 * 428 * Output: 429 * rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes) 430 * Inputs: 431 * v2hash: 16-byte NTLMv2 hash. 432 * C8: Challenge from server (8 bytes) 433 * client_data: client nonce (for LMv2) or the 434 * "blob" from ntlm_build_target_info (NTLMv2) 435 */ 436 static int 437 ntlm_v2_resp_hash(uchar_t *rhash, 438 const uchar_t *v2hash, const uchar_t *C8, 439 const uchar_t *client_data, size_t cdlen) 440 { 441 size_t dlen; 442 uchar_t *data = NULL; 443 444 /* data = concat(C8, client_data) */ 445 dlen = 8 + cdlen; 446 data = malloc(dlen); 447 if (data == NULL) 448 return (ENOMEM); 449 bcopy(C8, data, 8); 450 bcopy(client_data, data + 8, cdlen); 451 452 HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen); 453 454 free(data); 455 return (0); 456 } 457 458 /* 459 * Calculate an NTLMv2 session key (16 bytes). 460 */ 461 static void 462 ntlm_v2_session_key(uchar_t *ssn_key, 463 const uchar_t *v2hash, 464 const uchar_t *ntresp) 465 { 466 467 /* session key uses only 1st 16 bytes of ntresp */ 468 HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ); 469 } 470 471 472 /* 473 * Compute both the LMv2 response and the NTLMv2 response, 474 * and put them in the mbdata chains passed. This allocates 475 * mbuf chains in the output args, which the caller frees. 476 * Also computes the session key. 477 */ 478 int 479 ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, 480 struct mbdata *lm_mbp, struct mbdata *nt_mbp) 481 { 482 uchar_t *lmresp, *ntresp; 483 int err; 484 char *ucuser = NULL; /* upper-case user name */ 485 uchar_t v2hash[NTLM_HASH_SZ]; 486 struct mbuf *tim = ti_mbp->mb_top; 487 488 /* 489 * Convert the user name to upper-case, as 490 * that's what's used when computing LMv2 491 * and NTLMv2 responses. Note that the 492 * domain name is NOT upper-cased! 493 */ 494 if (ctx->ct_user[0] == '\0') 495 return (EINVAL); 496 ucuser = utf8_str_toupper(ctx->ct_user); 497 if (ucuser == NULL) 498 return (ENOMEM); 499 500 if ((err = mb_init(lm_mbp)) != 0) 501 goto out; 502 if ((err = mb_init(nt_mbp)) != 0) 503 goto out; 504 505 /* 506 * Compute the NTLMv2 hash 507 */ 508 err = ntlm_v2_hash(v2hash, ctx->ct_nthash, 509 ucuser, ctx->ct_domain); 510 if (err) 511 goto out; 512 513 /* 514 * Compute the LMv2 response, derived from 515 * the v2hash, the server challenge, and 516 * the client nonce (random bits). 517 * 518 * We compose it from two parts: 519 * 1: 16-byte response hash 520 * 2: Client nonce 521 */ 522 lmresp = mb_reserve(lm_mbp, NTLM_HASH_SZ); 523 err = ntlm_v2_resp_hash(lmresp, 524 v2hash, ctx->ct_srv_chal, 525 ctx->ct_clnonce, NTLM_CHAL_SZ); 526 if (err) 527 goto out; 528 mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); 529 530 /* 531 * Compute the NTLMv2 response, derived 532 * from the server challenge and the 533 * "target info." blob passed in. 534 * 535 * Again composed from two parts: 536 * 1: 16-byte response hash 537 * 2: "target info." blob 538 */ 539 ntresp = mb_reserve(nt_mbp, NTLM_HASH_SZ); 540 err = ntlm_v2_resp_hash(ntresp, 541 v2hash, ctx->ct_srv_chal, 542 (uchar_t *)tim->m_data, tim->m_len); 543 if (err) 544 goto out; 545 mb_put_mem(nt_mbp, tim->m_data, tim->m_len, MB_MSYSTEM); 546 547 /* 548 * Compute the session key 549 */ 550 ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp); 551 552 out: 553 if (err) { 554 mb_done(lm_mbp); 555 mb_done(nt_mbp); 556 } 557 free(ucuser); 558 559 return (err); 560 } 561 562 /* 563 * Helper for ntlm_build_target_info below. 564 * Put a name in the NTLMv2 "target info." blob. 565 */ 566 static void 567 smb_put_blob_name(struct mbdata *mbp, char *name, int type) 568 { 569 uint16_t *ucs = NULL; 570 int nlen; 571 572 if (name) 573 ucs = convert_utf8_to_leunicode(name); 574 if (ucs) 575 nlen = unicode_strlen(ucs); 576 else 577 nlen = 0; 578 579 nlen <<= 1; /* length in bytes, without null. */ 580 581 mb_put_uint16le(mbp, type); 582 mb_put_uint16le(mbp, nlen); 583 mb_put_mem(mbp, (char *)ucs, nlen, MB_MSYSTEM); 584 585 if (ucs) 586 free(ucs); 587 } 588 589 /* 590 * Build an NTLMv2 "target info." blob. When called from NTLMSSP, 591 * the list of names comes from the Type 2 message. Otherwise, 592 * we create the name list here. 593 */ 594 int 595 ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names, 596 struct mbdata *mbp) 597 { 598 struct timeval now; 599 uint64_t nt_time; 600 601 char *ucdom = NULL; /* user's domain */ 602 int err; 603 604 /* Get mbuf chain for the "target info". */ 605 if ((err = mb_init(mbp)) != 0) 606 return (err); 607 608 /* 609 * Get the "NT time" for the target info header. 610 */ 611 (void) gettimeofday(&now, 0); 612 smb_time_local2NT(&now, 0, &nt_time); 613 614 /* 615 * Build the "target info." block. 616 * 617 * Based on information at: 618 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response 619 * 620 * First the fixed-size part. 621 */ 622 mb_put_uint32le(mbp, 0x101); /* Blob signature */ 623 mb_put_uint32le(mbp, 0); /* reserved */ 624 mb_put_uint64le(mbp, nt_time); /* NT time stamp */ 625 mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); 626 mb_put_uint32le(mbp, 0); /* unknown */ 627 628 /* 629 * Now put the list of names, either from the 630 * NTLMSSP Type 2 message or composed here. 631 */ 632 if (names) { 633 err = mb_put_mem(mbp, names->m_data, names->m_len, MB_MSYSTEM); 634 } else { 635 /* Get upper-case names. */ 636 ucdom = utf8_str_toupper(ctx->ct_domain); 637 if (ucdom == NULL) { 638 err = ENOMEM; 639 goto out; 640 } 641 smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB); 642 smb_put_blob_name(mbp, NULL, NAMETYPE_EOL); 643 /* OK, that's the whole "target info." blob! */ 644 } 645 err = 0; 646 647 out: 648 free(ucdom); 649 return (err); 650 } 651 652 /* 653 * Build the MAC key (for SMB signing) 654 */ 655 int 656 ntlm_build_mac_key(struct smb_ctx *ctx, struct mbdata *ntresp_mbp) 657 { 658 struct mbuf *m; 659 size_t len; 660 char *p; 661 662 /* 663 * MAC_key = concat(session_key, nt_response) 664 */ 665 m = ntresp_mbp->mb_top; 666 len = NTLM_HASH_SZ + m->m_len; 667 if ((p = malloc(len)) == NULL) 668 return (ENOMEM); 669 ctx->ct_mackeylen = len; 670 ctx->ct_mackey = p; 671 memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 672 memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 673 674 return (0); 675 } 676 677 /* 678 * Helper for ntlmssp_put_type3 - Build the "key exchange key" 679 * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2. 680 * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7])) 681 */ 682 void 683 ntlm2_kxkey(struct smb_ctx *ctx, struct mbdata *lm_mbp, uchar_t *kxkey) 684 { 685 uchar_t data[NTLM_HASH_SZ]; 686 uchar_t *p = mtod(lm_mbp->mb_top, uchar_t *); 687 688 /* concat(ServerChallenge, LmResponse[0..7]) */ 689 memcpy(data, ctx->ct_srv_chal, NTLM_CHAL_SZ); 690 memcpy(data + NTLM_CHAL_SZ, p, NTLM_CHAL_SZ); 691 692 /* HMAC_MD5(SessionBaseKey, concat(...)) */ 693 HMACT64(kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ, 694 data, NTLM_HASH_SZ); 695 } 696