2 * Beware the LM hash is easy to crack (google for l0phtCrack)
3 * and though NTLM is more secure it is still breakable.
4 * Ntlmv2 is better and seen as good enough by the windows community.
5 * For real security use kerberos.
18 #define DEF_AUTH "ntlmv2"
21 MACkeylen = 40, /* MAC key len */
22 MAClen = 8, /* signature length */
23 MACoff = 14, /* sign. offset from start of SMB (not netbios) pkt */
24 Bliplen = 8, /* size of LMv2 client nonce */
28 dmp(char *s, int seq, void *buf, int n)
33 print("%s %3d ", s, seq);
35 for(i = 0; i < 16 && n > 0; i++, n--)
36 print("%02x ", *p++ & 0xff);
44 auth_plain(char *windom, char *keyp, uchar *chal, int len)
51 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s",
54 sysfatal("cannot get key - %r");
56 ap = emalloc9p(sizeof(Auth));
57 memset(ap, 0, sizeof(ap));
58 ap->user = estrdup9p(up->user);
59 ap->windom = estrdup9p(windom);
61 ap->resp[0] = estrdup9p(up->passwd);
62 ap->len[0] = strlen(up->passwd);
63 memset(up->passwd, 0, strlen(up->passwd));
70 auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
77 err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
78 auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
81 sysfatal("cannot get key - %r");
83 ap = emalloc9p(sizeof(Auth));
84 memset(ap, 0, sizeof(ap));
85 ap->user = estrdup9p(user);
86 ap->windom = estrdup9p(windom);
89 ap->len[0] = sizeof(mcr.LMresp);
90 ap->resp[0] = emalloc9p(ap->len[0]);
91 memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);
94 ap->len[1] = sizeof(mcr.NTresp);
95 ap->resp[1] = emalloc9p(ap->len[1]);
96 memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);
102 * NTLM response only, the LM response is a just
103 * copy of the NTLM one. we do this because the lm
104 * response is easily reversed - Google for l0pht
108 auth_ntlm(char *windom, char *keyp, uchar *chal, int len)
112 if((ap = auth_lm_and_ntlm(windom, keyp, chal, len)) == nil)
116 ap->len[0] = ap->len[1];
117 ap->resp[0] = emalloc9p(ap->len[0]);
118 memcpy(ap->resp[0], ap->resp[1], ap->len[0]);
123 * This is not really nescessary as all fields hmac_md5'ed
124 * in the ntlmv2 protocol are less than 64 bytes long, however
125 * I still do this for completeness
128 hmac_t64(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest,
133 return hmac_md5(data, dlen, key, klen, digest, state);
138 putname(uchar *buf, int len, char *name, int type)
146 *p++ = 0; /* 16bit: name type */
148 n = utflen(name) * 2;
150 *p++ = n >> 8; /* 16bit: name length */
153 while(*d != 0 && p-buf < len-8){
154 d += chartorune(&r, d);
158 } /* var: actual name */
164 ntv2_blob(uchar *blob, int len, char *windom)
168 enum { /* name types */
169 Beof, /* end of name list */
170 Bhost, /* Netbios host name */
171 Bdomain, /* Windows Domain name (NT) */
172 Bdnshost, /* DNS host name */
173 Bdnsdomain, /* DNS domain name */
177 *p++ = 1; /* 8bit: response type */
178 *p++ = 1; /* 8bit: max response type understood by client */
180 *p++ = 0; /* 16bit: reserved */
183 *p++ = 0; /* 32bit: unknown */
192 *p++ = t; /* 64bit: time in NT format */
202 p += 8; /* 64bit: client nonce */
204 *p++ = 0; /* 32bit: unknown data */
209 p += putname(p, len - (p-blob), windom, Bdomain);
210 p += putname(p, len - (p-blob), "", Beof);
216 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
221 uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen];
222 uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen],
228 up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s",
231 sysfatal("cannot get key - %r");
233 ap = emalloc9p(sizeof(Auth));
234 memset(ap, 0, sizeof(ap));
236 /* Standard says unlimited length, experience says 128 max */
237 if((n = strlen(up->passwd)) > 128)
240 ds = md4(nil, 0, nil, nil);
241 for(i=0, p=up->passwd; i < n; i++) {
242 p += chartorune(&r, p);
248 md4(nil, 0, v1hash, ds);
251 * Some documentation insists that the username must be forced to
252 * uppercase, but the domain name should not be. Other shows both
253 * being forced to uppercase. I am pretty sure this is irrevevant as the
254 * domain name passed from the remote server always seems to be in
257 ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil);
260 u += chartorune(&r, u);
263 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
265 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
270 u += chartorune(&r, u);
272 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
274 hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
276 hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds);
277 ap->user = estrdup9p(up->user);
278 ap->windom = estrdup9p(windom);
282 genrandom(blip, Bliplen);
283 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
284 hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds);
285 ap->len[0] = MD5dlen+Bliplen;
286 ap->resp[0] = emalloc9p(ap->len[0]);
287 memcpy(ap->resp[0], lm_hmac, MD5dlen);
288 memcpy(ap->resp[0]+MD5dlen, blip, Bliplen);
290 /* LM v2 session key */
291 hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil);
294 ap->mackey[0] = emalloc9p(MACkeylen);
295 memcpy(ap->mackey[0], lm_sesskey, MD5dlen);
296 memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
299 n = ntv2_blob(blob, sizeof blob, windom);
300 ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
301 hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
302 ap->len[1] = MD5dlen+n;
303 ap->resp[1] = emalloc9p(ap->len[1]);
304 memcpy(ap->resp[1], nt_hmac, MD5dlen);
305 memcpy(ap->resp[1]+MD5dlen, blob, n);
308 * v2hash definitely OK by
309 * the time we get here.
311 /* NTLM v2 session key */
312 hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil);
314 /* NTLM v2 MAC key */
315 ap->mackey[1] = emalloc9p(MACkeylen);
316 memcpy(ap->mackey[1], nt_sesskey, MD5dlen);
317 memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen);
325 Auth *(*func)(char *, char *, uchar *, int);
327 { "plain", auth_plain },
328 { "lm+ntlm", auth_lm_and_ntlm },
329 { "ntlm", auth_ntlm },
330 { "ntlmv2", auth_ntlmv2 },
331 // { "kerberos", auth_kerberos },
339 fprint(2, "supported auth methods:\t");
340 for(i = 0; i < nelem(methods); i++)
341 fprint(2, "%s ", methods[i].name);
347 getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len)
354 if((secmode & SECMODE_PW_ENCRYPT) == 0)
355 sysfatal("plaintext authentication required, use '-a plain'");
359 for(i = 0; i < nelem(methods); i++)
360 if(strcmp(methods[i].name, name) == 0){
361 ap = methods[i].func(windom, keyp, chal, len);
366 fprint(2, "%s: %s - unknown auth method\n", argv0, name);
367 autherr(); /* never returns */
373 genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar ours[MAClen])
376 uchar *sig, digest[MD5dlen], theirs[MAClen];
379 memcpy(theirs, sig, MAClen);
381 memset(sig, 0, MAClen);
387 ds = md5(key, MACkeylen, nil, nil);
388 md5(buf, len, digest, ds);
389 memcpy(ours, digest, MAClen);
391 return memcmp(theirs, ours, MAClen);
395 macsign(Pkt *p, int seq)
398 uchar *sig, *buf, mac[MAClen];
400 sig = p->buf + NBHDRLEN + MACoff;
401 buf = p->buf + NBHDRLEN;
402 len = (p->pos - p->buf) - NBHDRLEN;
406 dmp("rx", seq, sig, MAClen);
410 memcpy(mac, "BSRSPYL ", 8); /* no idea, ask MS */
412 rc = genmac(buf, len, seq, p->s->auth->mackey[0], mac);
415 dmp("tx", seq, mac, MAClen);
417 memcpy(sig, mac, MAClen);