2 * Copyright (c) 2000-2001, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
36 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
37 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
41 * NTLM support functions
43 * Some code from the driver: smb_smb.c, smb_crypt.c
46 #include <sys/errno.h>
47 #include <sys/types.h>
55 #include <netsmb/smb_lib.h>
59 #include "smb_crypt.h"
64 * ntlm_compute_lm_hash
66 * Given a password, compute the LM hash.
67 * a.k.a. ResponseKeyLM in [MS-NLMP]
70 * hash: 16-byte "LanMan" (LM) hash (normally ctx->ct_lmhash)
72 * ucpw: User's password, upper-case UTF-8 string.
74 * Source: Implementing CIFS (Chris Hertel)
76 * P14 = UCPW padded to 14-bytes, or truncated (as needed)
77 * result = Encrypt(Key=P14, Data=MagicString)
80 ntlm_compute_lm_hash(uchar_t
*hash
, const char *pass
)
82 static const uchar_t M8
[8] = "KGS!@#$%";
87 /* First, convert the p/w to upper case. */
88 ucpw
= utf8_str_toupper(pass
);
92 /* Pad or truncate the upper-case P/W as needed. */
93 bzero(P14
, sizeof (P14
));
94 (void) strncpy((char *)P14
, ucpw
, 14);
96 /* Compute the hash. */
97 err
= smb_encrypt_DES(hash
, NTLM_HASH_SZ
,
105 * ntlm_compute_nt_hash
107 * Given a password, compute the NT hash.
108 * a.k.a. the ResponseKeyNT in [MS-NLMP]
111 * hash: 16-byte "NT" hash (normally ctx->ct_nthash)
113 * upw: User's password, mixed-case UCS-2LE.
114 * pwlen: Size (in bytes) of upw
117 ntlm_compute_nt_hash(uchar_t
*hash
, const char *pass
)
120 uint16_t *unipw
= NULL
;
123 /* First, convert the password to unicode. */
124 unipw
= convert_utf8_to_leunicode(pass
);
127 pwsz
= unicode_strlen(unipw
) << 1;
129 /* Compute the hash. */
131 MD4Update(&ctx
, unipw
, pwsz
);
132 MD4Final(hash
, &ctx
);
140 * a.k.a. DESL() in [MS-NLMP]
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)
147 ntlm_v1_response(uchar_t
*resp
,
149 const uchar_t
*chal
, int clen
)
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
158 bzero(&S21
, sizeof (S21
));
159 bcopy(hash
, S21
, NTLM_HASH_SZ
);
161 /* padded LM Hash -> LM Response */
162 err
= smb_encrypt_DES(resp
, NTLM_V1_RESP_SZ
,
163 S21
, 21, chal
, clen
);
168 * Calculate an NTLMv1 session key (16 bytes).
171 ntlm_v1_session_key(uchar_t
*ssn_key
, const uchar_t
*nt_hash
)
176 MD4Update(&md4
, nt_hash
, NTLM_HASH_SZ
);
177 MD4Final(ssn_key
, &md4
);
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.
186 ntlm_put_v1_responses(struct smb_ctx
*ctx
,
187 struct mbdata
*lm_mbp
, struct mbdata
*nt_mbp
)
189 uchar_t
*lmresp
, *ntresp
;
192 /* Get mbuf chain for the LM response. */
193 if ((err
= mb_init_sz(lm_mbp
, NTLM_V1_RESP_SZ
)) != 0)
196 /* Get mbuf chain for the NT response. */
197 if ((err
= mb_init_sz(nt_mbp
, NTLM_V1_RESP_SZ
)) != 0)
201 * Compute the NTLM response, derived from
202 * the challenge and the NT hash (a.k.a ResponseKeyNT)
204 err
= mb_fit(nt_mbp
, NTLM_V1_RESP_SZ
, (char **)&ntresp
);
207 bzero(ntresp
, NTLM_V1_RESP_SZ
);
208 err
= ntlm_v1_response(ntresp
, ctx
->ct_nthash
,
209 ctx
->ct_srv_chal
, NTLM_CHAL_SZ
);
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.
217 err
= mb_fit(lm_mbp
, NTLM_V1_RESP_SZ
, (char **)&lmresp
);
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
);
230 * Compute the session key
232 ntlm_v1_session_key(ctx
->ct_ssn_key
, ctx
->ct_nthash
);
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.
244 * This allocates mbuf chains in the output args (caller frees).
247 ntlm_put_v1x_responses(struct smb_ctx
*ctx
,
248 struct mbdata
*lm_mbp
, struct mbdata
*nt_mbp
)
251 uchar_t challenges
[2 * NTLM_CHAL_SZ
];
252 uchar_t digest
[NTLM_HASH_SZ
];
253 uchar_t
*lmresp
, *ntresp
;
256 /* Get mbuf chain for the LM response. */
257 if ((err
= mb_init_sz(lm_mbp
, NTLM_V1_RESP_SZ
)) != 0)
260 /* Get mbuf chain for the NT response. */
261 if ((err
= mb_init_sz(nt_mbp
, NTLM_V1_RESP_SZ
)) != 0)
265 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
267 memcpy(challenges
, ctx
->ct_srv_chal
, NTLM_CHAL_SZ
);
268 memcpy(challenges
+ NTLM_CHAL_SZ
, ctx
->ct_clnonce
, NTLM_CHAL_SZ
);
271 * digest = MD5(challenges)
274 MD5Update(&context
, challenges
, sizeof (challenges
));
275 MD5Final(digest
, &context
);
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.
282 err
= mb_fit(nt_mbp
, NTLM_V1_RESP_SZ
, (char **)&ntresp
);
285 bzero(ntresp
, NTLM_V1_RESP_SZ
);
286 err
= ntlm_v1_response(ntresp
, ctx
->ct_nthash
,
287 digest
, NTLM_CHAL_SZ
);
290 * With "Extended Session Security", the LM response
291 * is simply the client challenge (nonce) padded out.
293 err
= mb_fit(lm_mbp
, NTLM_V1_RESP_SZ
, (char **)&lmresp
);
296 bzero(lmresp
, NTLM_V1_RESP_SZ
);
297 memcpy(lmresp
, ctx
->ct_clnonce
, NTLM_CHAL_SZ
);
300 * Compute the session key
302 ntlm_v1_session_key(ctx
->ct_ssn_key
, ctx
->ct_nthash
);
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.
313 * Output: digest (16-bytes)
316 HMACT64(uchar_t
*digest
,
317 const uchar_t
*key
, size_t key_len
,
318 const uchar_t
*data
, size_t data_len
)
321 uchar_t k_ipad
[64]; /* inner padding - key XORd with ipad */
322 uchar_t k_opad
[64]; /* outer padding - key XORd with opad */
325 /* if key is longer than 64 bytes use only the first 64 bytes */
330 * The HMAC-MD5 (and HMACT64) transform looks like:
332 * MD5(K XOR opad, MD5(K XOR ipad, data))
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.
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
);
346 /* XOR key with ipad and opad values */
347 for (i
= 0; i
< 64; i
++) {
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 */
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 */
371 * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
372 * and the destination (machine or domain name).
375 * v2hash: 16-byte NTLMv2 hash.
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.
382 ntlm_v2_hash(uchar_t
*v2hash
, const uchar_t
*v1hash
,
383 const char *user
, const char *destination
)
387 uint16_t *ucs2data
= NULL
;
388 char *utf8data
= NULL
;
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.
397 /* utf8data = concat(user, dest) */
399 dlen
= strlen(destination
);
400 utf8data
= malloc(ulen
+ dlen
+ 1);
401 if (utf8data
== NULL
)
403 bcopy(user
, utf8data
, ulen
);
404 bcopy(destination
, utf8data
+ ulen
, dlen
+ 1);
406 /* Convert to UCS-2LE */
407 ucs2data
= convert_utf8_to_leunicode(utf8data
);
408 if (ucs2data
== NULL
)
410 ucs2len
= 2 * unicode_strlen(ucs2data
);
412 HMACT64(v2hash
, v1hash
, NTLM_HASH_SZ
,
413 (uchar_t
*)ucs2data
, ucs2len
);
422 * Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
423 * The full response is composed by the caller by
424 * appending the client_data to the returned hash.
427 * rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes)
429 * v2hash: 16-byte NTLMv2 hash.
430 * C8: Challenge from server (8 bytes)
431 * client_data: client nonce (for LMv2) or the
432 * "blob" from ntlm_build_target_info (NTLMv2)
435 ntlm_v2_resp_hash(uchar_t
*rhash
,
436 const uchar_t
*v2hash
, const uchar_t
*C8
,
437 const uchar_t
*client_data
, size_t cdlen
)
440 uchar_t
*data
= NULL
;
442 /* data = concat(C8, client_data) */
448 bcopy(client_data
, data
+ 8, cdlen
);
450 HMACT64(rhash
, v2hash
, NTLM_HASH_SZ
, data
, dlen
);
457 * Calculate an NTLMv2 session key (16 bytes).
460 ntlm_v2_session_key(uchar_t
*ssn_key
,
461 const uchar_t
*v2hash
,
462 const uchar_t
*ntresp
)
465 /* session key uses only 1st 16 bytes of ntresp */
466 HMACT64(ssn_key
, v2hash
, NTLM_HASH_SZ
, ntresp
, NTLM_HASH_SZ
);
471 * Compute both the LMv2 response and the NTLMv2 response,
472 * and put them in the mbdata chains passed. This allocates
473 * mbuf chains in the output args, which the caller frees.
474 * Also computes the session key.
477 ntlm_put_v2_responses(struct smb_ctx
*ctx
, struct mbdata
*ti_mbp
,
478 struct mbdata
*lm_mbp
, struct mbdata
*nt_mbp
)
480 uchar_t
*lmresp
, *ntresp
;
482 char *ucuser
= NULL
; /* upper-case user name */
483 uchar_t v2hash
[NTLM_HASH_SZ
];
484 struct mbuf
*tim
= ti_mbp
->mb_top
;
487 * Convert the user name to upper-case, as
488 * that's what's used when computing LMv2
489 * and NTLMv2 responses. Note that the
490 * domain name is NOT upper-cased!
492 if (ctx
->ct_user
[0] == '\0')
494 ucuser
= utf8_str_toupper(ctx
->ct_user
);
498 if ((err
= mb_init(lm_mbp
)) != 0)
500 if ((err
= mb_init(nt_mbp
)) != 0)
504 * Compute the NTLMv2 hash
506 err
= ntlm_v2_hash(v2hash
, ctx
->ct_nthash
,
507 ucuser
, ctx
->ct_domain
);
512 * Compute the LMv2 response, derived from
513 * the v2hash, the server challenge, and
514 * the client nonce (random bits).
516 * We compose it from two parts:
517 * 1: 16-byte response hash
520 lmresp
= mb_reserve(lm_mbp
, NTLM_HASH_SZ
);
521 err
= ntlm_v2_resp_hash(lmresp
,
522 v2hash
, ctx
->ct_srv_chal
,
523 ctx
->ct_clnonce
, NTLM_CHAL_SZ
);
526 mb_put_mem(lm_mbp
, ctx
->ct_clnonce
, NTLM_CHAL_SZ
, MB_MSYSTEM
);
529 * Compute the NTLMv2 response, derived
530 * from the server challenge and the
531 * "target info." blob passed in.
533 * Again composed from two parts:
534 * 1: 16-byte response hash
535 * 2: "target info." blob
537 ntresp
= mb_reserve(nt_mbp
, NTLM_HASH_SZ
);
538 err
= ntlm_v2_resp_hash(ntresp
,
539 v2hash
, ctx
->ct_srv_chal
,
540 (uchar_t
*)tim
->m_data
, tim
->m_len
);
543 mb_put_mem(nt_mbp
, tim
->m_data
, tim
->m_len
, MB_MSYSTEM
);
546 * Compute the session key
548 ntlm_v2_session_key(ctx
->ct_ssn_key
, v2hash
, ntresp
);
561 * Helper for ntlm_build_target_info below.
562 * Put a name in the NTLMv2 "target info." blob.
565 smb_put_blob_name(struct mbdata
*mbp
, char *name
, int type
)
567 uint16_t *ucs
= NULL
;
571 ucs
= convert_utf8_to_leunicode(name
);
573 nlen
= unicode_strlen(ucs
);
577 nlen
<<= 1; /* length in bytes, without null. */
579 mb_put_uint16le(mbp
, type
);
580 mb_put_uint16le(mbp
, nlen
);
581 mb_put_mem(mbp
, (char *)ucs
, nlen
, MB_MSYSTEM
);
587 * Build an NTLMv2 "target info." blob. When called from NTLMSSP,
588 * the list of names comes from the Type 2 message. Otherwise,
589 * we create the name list here.
592 ntlm_build_target_info(struct smb_ctx
*ctx
, struct mbuf
*names
,
598 char *ucdom
= NULL
; /* user's domain */
601 /* Get mbuf chain for the "target info". */
602 if ((err
= mb_init(mbp
)) != 0)
606 * Get the "NT time" for the target info header.
608 (void) gettimeofday(&now
, 0);
609 smb_time_local2NT(&now
, 0, &nt_time
);
612 * Build the "target info." block.
614 * Based on information at:
615 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
617 * First the fixed-size part.
619 mb_put_uint32le(mbp
, 0x101); /* Blob signature */
620 mb_put_uint32le(mbp
, 0); /* reserved */
621 mb_put_uint64le(mbp
, nt_time
); /* NT time stamp */
622 mb_put_mem(mbp
, ctx
->ct_clnonce
, NTLM_CHAL_SZ
, MB_MSYSTEM
);
623 mb_put_uint32le(mbp
, 0); /* unknown */
626 * Now put the list of names, either from the
627 * NTLMSSP Type 2 message or composed here.
630 err
= mb_put_mem(mbp
, names
->m_data
, names
->m_len
, MB_MSYSTEM
);
632 /* Get upper-case names. */
633 ucdom
= utf8_str_toupper(ctx
->ct_domain
);
638 smb_put_blob_name(mbp
, ucdom
, NAMETYPE_DOMAIN_NB
);
639 smb_put_blob_name(mbp
, NULL
, NAMETYPE_EOL
);
640 /* OK, that's the whole "target info." blob! */
650 * Build the MAC key (for SMB signing)
653 ntlm_build_mac_key(struct smb_ctx
*ctx
, struct mbdata
*ntresp_mbp
)
660 * MAC_key = concat(session_key, nt_response)
662 m
= ntresp_mbp
->mb_top
;
663 len
= NTLM_HASH_SZ
+ m
->m_len
;
664 if ((p
= malloc(len
)) == NULL
)
666 ctx
->ct_mackeylen
= len
;
668 memcpy(p
, ctx
->ct_ssn_key
, NTLM_HASH_SZ
);
669 memcpy(p
+ NTLM_HASH_SZ
, m
->m_data
, m
->m_len
);
675 * Helper for ntlmssp_put_type3 - Build the "key exchange key"
676 * used when we have both NTLM(v1) and NTLMSSP_NEGOTIATE_NTLM2.
677 * HMAC_MD5(SessionBaseKey, concat(ServerChallenge, LmResponse[0..7]))
680 ntlm2_kxkey(struct smb_ctx
*ctx
, struct mbdata
*lm_mbp
, uchar_t
*kxkey
)
682 uchar_t data
[NTLM_HASH_SZ
];
683 uchar_t
*p
= mtod(lm_mbp
->mb_top
, uchar_t
*);
685 /* concat(ServerChallenge, LmResponse[0..7]) */
686 memcpy(data
, ctx
->ct_srv_chal
, NTLM_CHAL_SZ
);
687 memcpy(data
+ NTLM_CHAL_SZ
, p
, NTLM_CHAL_SZ
);
689 /* HMAC_MD5(SessionBaseKey, concat(...)) */
690 HMACT64(kxkey
, ctx
->ct_ssn_key
, NTLM_HASH_SZ
,