2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5 * http://www.strataware.com/
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by Eric Rosenquist. The name of the author may not be used to
15 * endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
26 * Implemented LANManager type password response to MS-CHAP challenges.
27 * Now pppd provides both NT style and LANMan style blocks, and the
28 * prefered is set by option "ms-lanman". Default is to use NT.
29 * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
31 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
35 * Modifications by Frank Cusack, frank@google.com, March 2002.
37 * Implemented MS-CHAPv2 functionality. Heavily based on
38 * sample implementation in RFC 2759.
41 #define RCSID "$Id: chap_ms.c,v 1.18 2002/03/05 15:14:04 dfs Exp $"
49 #include <sys/types.h>
66 static const char rcsid[] = RCSID;
69 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
70 static void ascii2unicode __P((char[], int, u_char[]));
71 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
72 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
73 static void DesEncrypt __P((u_char *, u_char *, u_char[8]));
74 static void MakeKey __P((u_char *, u_char *));
75 static u_char Get7Bits __P((u_char *, int));
76 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
77 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
79 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
83 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
87 static void Expand __P((u_char *, u_char *));
88 static void Collapse __P((u_char *, u_char *));
91 extern double drand48 __P((void));
94 bool ms_lanman = 0; /* Use LanMan password instead of NT */
95 /* Has meaning only with MS-CHAP challenges */
99 ChallengeResponse(u_char *challenge,
100 u_char PasswordHash[MD4_SIGNATURE_SIZE],
103 char ZPasswordHash[21];
105 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
106 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
109 dbglog("ChallengeResponse - ZPasswordHash %.*B",
110 sizeof(ZPasswordHash), ZPasswordHash);
113 DesEncrypt(challenge, ZPasswordHash + 0, &response[0]);
114 DesEncrypt(challenge, ZPasswordHash + 7, &response[8]);
115 DesEncrypt(challenge, ZPasswordHash + 14, &response[16]);
118 dbglog("ChallengeResponse - response %.24B", response);
125 DesEncrypt(u_char *clear, u_char *key, u_char cipher[8])
128 u_char crypt_key[66];
129 u_char des_input[66];
131 MakeKey(key, des_key);
133 Expand(des_key, crypt_key);
137 CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
140 Expand(clear, des_input);
141 encrypt(des_input, 0);
142 Collapse(des_input, cipher);
145 CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
149 #else /* USE_CRYPT */
152 DesEncrypt(u_char *clear, u_char *key, u_char cipher[8])
155 des_key_schedule key_schedule;
157 MakeKey(key, des_key);
159 des_set_key(&des_key, key_schedule);
162 CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
165 des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
168 CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
172 #endif /* USE_CRYPT */
175 static u_char Get7Bits(u_char *input, int startBit)
177 register unsigned int word;
179 word = (unsigned)input[startBit / 8] << 8;
180 word |= (unsigned)input[startBit / 8 + 1];
182 word >>= 15 - (startBit % 8 + 7);
189 /* in == 8-byte string (expanded version of the 56-bit key)
190 * out == 64-byte string where each byte is either 1 or 0
191 * Note that the low-order "bit" is always ignored by by setkey()
193 static void Expand(u_char *in, u_char *out)
198 for(i = 0; i < 64; in++){
200 for(j = 7; j >= 0; j--)
201 *out++ = (c >> j) & 01;
206 /* The inverse of Expand
208 static void Collapse(u_char *in, u_char *out)
214 for (i = 0; i < 64; i += 8, out++) {
216 for (j = 7; j >= 0; j--, in++)
223 static void MakeKey(u_char *key, u_char *des_key)
225 des_key[0] = Get7Bits(key, 0);
226 des_key[1] = Get7Bits(key, 7);
227 des_key[2] = Get7Bits(key, 14);
228 des_key[3] = Get7Bits(key, 21);
229 des_key[4] = Get7Bits(key, 28);
230 des_key[5] = Get7Bits(key, 35);
231 des_key[6] = Get7Bits(key, 42);
232 des_key[7] = Get7Bits(key, 49);
235 des_set_odd_parity((des_cblock *)des_key);
239 CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
240 CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
246 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
247 char *username, u_char Challenge[8])
250 SHA1_CTX sha1Context;
251 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
253 SHA1_Init(&sha1Context);
254 SHA1_Update(&sha1Context, PeerChallenge, 16);
255 SHA1_Update(&sha1Context, rchallenge, 16);
256 SHA1_Update(&sha1Context, username, strlen(username));
257 SHA1_Final(sha1Hash, &sha1Context);
259 BCOPY(sha1Hash, Challenge, 8);
263 * Convert the ASCII version of the password to Unicode.
264 * This implicitly supports 8-bit ISO8859/1 characters.
265 * This gives us the little-endian representation, which
266 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
267 * is machine-dependent.)
270 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
274 BZERO(unicode, ascii_len * 2);
275 for (i = 0; i < ascii_len; i++)
276 unicode[i * 2] = (u_char) ascii[i];
280 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
283 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
284 int mdlen = secret_len;
286 int mdlen = secret_len * 8;
290 MD4Init(&md4Context);
291 MD4Update(&md4Context, secret, mdlen);
292 MD4Final(hash, &md4Context);
297 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
298 u_char NTResponse[24])
300 u_char unicodePassword[MAX_NT_PASSWORD * 2];
301 u_char PasswordHash[MD4_SIGNATURE_SIZE];
303 /* Hash the Unicode version of the secret (== password). */
304 ascii2unicode(secret, secret_len, unicodePassword);
305 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
307 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
311 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
312 char *secret, int secret_len, u_char NTResponse[24])
314 u_char unicodePassword[MAX_NT_PASSWORD * 2];
315 u_char PasswordHash[MD4_SIGNATURE_SIZE];
318 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
320 /* Hash the Unicode version of the secret (== password). */
321 ascii2unicode(secret, secret_len, unicodePassword);
322 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
324 ChallengeResponse(Challenge, PasswordHash, NTResponse);
328 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
331 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
332 u_char LMResponse[24])
335 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
336 u_char PasswordHash[MD4_SIGNATURE_SIZE];
338 /* LANMan password is case insensitive */
339 BZERO(UcasePassword, sizeof(UcasePassword));
340 for (i = 0; i < secret_len; i++)
341 UcasePassword[i] = (u_char)toupper(secret[i]);
342 DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
343 DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
344 ChallengeResponse(rchallenge, PasswordHash, LMResponse);
350 GenerateAuthenticatorResponse(char *secret, int secret_len,
351 u_char NTResponse[24], u_char PeerChallenge[16],
352 u_char *rchallenge, char *username,
353 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
356 * "Magic" constants used in response generation, from RFC 2759.
358 u_char Magic1[39] = /* "Magic server to client signing constant" */
359 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
360 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
361 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
362 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
363 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
364 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
365 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
366 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
367 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
371 SHA1_CTX sha1Context;
372 u_char unicodePassword[MAX_NT_PASSWORD * 2];
373 u_char PasswordHash[MD4_SIGNATURE_SIZE];
374 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
375 u_char Digest[SHA1_SIGNATURE_SIZE];
378 /* Hash (x2) the Unicode version of the secret (== password). */
379 ascii2unicode(secret, secret_len, unicodePassword);
380 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
381 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
383 SHA1_Init(&sha1Context);
384 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
385 SHA1_Update(&sha1Context, NTResponse, 24);
386 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
387 SHA1_Final(Digest, &sha1Context);
389 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
391 SHA1_Init(&sha1Context);
392 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
393 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
394 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
395 SHA1_Final(Digest, &sha1Context);
397 /* Convert to ASCII hex string. */
398 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
399 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
404 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
405 MS_ChapResponse *response)
408 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
410 BZERO(response, sizeof(response));
412 /* Calculate both always */
413 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
416 ChapMS_LANMan(rchallenge, secret, secret_len, response);
418 /* prefered method is set by option */
419 response->UseNT[0] = !ms_lanman;
421 response->UseNT[0] = 1;
428 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
429 * is filled in. Call this way when generating a response.
430 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
431 * Call this way when verifying a response.
433 * response->PeerChallenge is then used for calculation of the
434 * Authenticator Response.
437 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
438 char *user, char *secret, int secret_len, MS_Chap2Response *response,
439 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
441 u_char *p = response->PeerChallenge;
444 BZERO(response, sizeof(response));
446 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
448 for (i = 0; i < sizeof(response->PeerChallenge); i++)
449 *p++ = (u_char) (drand48() * 0xff);
451 BCOPY(PeerChallenge, response->PeerChallenge,
452 sizeof(response->PeerChallenge));
454 /* Generate the NT-Response */
455 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
456 secret, secret_len, response->NTResp);
458 /* Generate the Authenticator Response. */
459 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
460 response->PeerChallenge, rchallenge,