2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * 3. The name(s) of the authors of this software must not be used to
19 * endorse or promote products derived from this software without
20 * prior written permission.
22 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
34 * Implemented LANManager type password response to MS-CHAP challenges.
35 * Now pppd provides both NT style and LANMan style blocks, and the
36 * prefered is set by option "ms-lanman". Default is to use NT.
37 * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
39 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
43 * Modifications by Frank Cusack, frank@google.com, March 2002.
45 * Implemented MS-CHAPv2 functionality, heavily based on sample
46 * implementation in RFC 2759. Implemented MPPE functionality,
47 * heavily based on sample implementation in RFC 3079.
48 * Copyright (c) 2002 Google, Inc.
51 #define RCSID "$Id: chap_ms.c,v 1.25 2002/12/04 23:03:32 paulus Exp $"
59 #include <sys/types.h>
70 static const char rcsid[] = RCSID;
73 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
74 static void ascii2unicode __P((char[], int, u_char[]));
75 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
76 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
77 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
78 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
80 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
84 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
88 static void Set_Start_Key __P((u_char *, char *, int));
89 static void SetMasterKeys __P((char *, int, u_char[24], int));
92 extern double drand48 __P((void));
95 bool ms_lanman = 0; /* Use LanMan password instead of NT */
96 /* Has meaning only with MS-CHAP challenges */
100 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
101 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
105 ChallengeResponse(u_char *challenge,
106 u_char PasswordHash[MD4_SIGNATURE_SIZE],
109 u_char ZPasswordHash[21];
111 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
112 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
115 dbglog("ChallengeResponse - ZPasswordHash %.*B",
116 sizeof(ZPasswordHash), ZPasswordHash);
119 (void) DesSetkey(ZPasswordHash + 0);
120 DesEncrypt(challenge, response + 0);
121 (void) DesSetkey(ZPasswordHash + 7);
122 DesEncrypt(challenge, response + 8);
123 (void) DesSetkey(ZPasswordHash + 14);
124 DesEncrypt(challenge, response + 16);
127 dbglog("ChallengeResponse - response %.24B", response);
132 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
133 char *username, u_char Challenge[8])
136 SHA1_CTX sha1Context;
137 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
140 /* remove domain from "domain\username" */
141 if ((user = strrchr(username, '\\')) != NULL)
146 SHA1_Init(&sha1Context);
147 SHA1_Update(&sha1Context, PeerChallenge, 16);
148 SHA1_Update(&sha1Context, rchallenge, 16);
149 SHA1_Update(&sha1Context, user, strlen(user));
150 SHA1_Final(sha1Hash, &sha1Context);
152 BCOPY(sha1Hash, Challenge, 8);
156 * Convert the ASCII version of the password to Unicode.
157 * This implicitly supports 8-bit ISO8859/1 characters.
158 * This gives us the little-endian representation, which
159 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
160 * is machine-dependent.)
163 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
167 BZERO(unicode, ascii_len * 2);
168 for (i = 0; i < ascii_len; i++)
169 unicode[i * 2] = (u_char) ascii[i];
173 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
176 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
177 int mdlen = secret_len;
179 int mdlen = secret_len * 8;
183 MD4Init(&md4Context);
184 MD4Update(&md4Context, secret, mdlen);
185 MD4Final(hash, &md4Context);
190 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
191 u_char NTResponse[24])
193 u_char unicodePassword[MAX_NT_PASSWORD * 2];
194 u_char PasswordHash[MD4_SIGNATURE_SIZE];
196 /* Hash the Unicode version of the secret (== password). */
197 ascii2unicode(secret, secret_len, unicodePassword);
198 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
200 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
204 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
205 char *secret, int secret_len, u_char NTResponse[24])
207 u_char unicodePassword[MAX_NT_PASSWORD * 2];
208 u_char PasswordHash[MD4_SIGNATURE_SIZE];
211 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
213 /* Hash the Unicode version of the secret (== password). */
214 ascii2unicode(secret, secret_len, unicodePassword);
215 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
217 ChallengeResponse(Challenge, PasswordHash, NTResponse);
221 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
224 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
225 MS_ChapResponse *response)
228 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
229 u_char PasswordHash[MD4_SIGNATURE_SIZE];
231 /* LANMan password is case insensitive */
232 BZERO(UcasePassword, sizeof(UcasePassword));
233 for (i = 0; i < secret_len; i++)
234 UcasePassword[i] = (u_char)toupper(secret[i]);
235 (void) DesSetkey(UcasePassword + 0);
236 DesEncrypt( StdText, PasswordHash + 0 );
237 (void) DesSetkey(UcasePassword + 7);
238 DesEncrypt( StdText, PasswordHash + 8 );
239 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
245 GenerateAuthenticatorResponse(char *secret, int secret_len,
246 u_char NTResponse[24], u_char PeerChallenge[16],
247 u_char *rchallenge, char *username,
248 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
251 * "Magic" constants used in response generation, from RFC 2759.
253 u_char Magic1[39] = /* "Magic server to client signing constant" */
254 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
255 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
256 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
257 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
258 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
259 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
260 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
261 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
262 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
266 SHA1_CTX sha1Context;
267 u_char unicodePassword[MAX_NT_PASSWORD * 2];
268 u_char PasswordHash[MD4_SIGNATURE_SIZE];
269 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
270 u_char Digest[SHA1_SIGNATURE_SIZE];
273 /* Hash (x2) the Unicode version of the secret (== password). */
274 ascii2unicode(secret, secret_len, unicodePassword);
275 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
276 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
278 SHA1_Init(&sha1Context);
279 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
280 SHA1_Update(&sha1Context, NTResponse, 24);
281 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
282 SHA1_Final(Digest, &sha1Context);
284 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
286 SHA1_Init(&sha1Context);
287 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
288 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
289 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
290 SHA1_Final(Digest, &sha1Context);
292 /* Convert to ASCII hex string. */
293 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
294 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
300 * Set mppe_xxxx_key from the NTPasswordHashHash.
301 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
304 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
306 SHA1_CTX sha1Context;
307 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
309 SHA1_Init(&sha1Context);
310 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
311 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
312 SHA1_Update(&sha1Context, rchallenge, 8);
313 SHA1_Final(Digest, &sha1Context);
315 /* Same key in both directions. */
316 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
317 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
321 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
324 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
326 u_char unicodePassword[MAX_NT_PASSWORD * 2];
327 u_char PasswordHash[MD4_SIGNATURE_SIZE];
328 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
330 /* Hash (x2) the Unicode version of the secret (== password). */
331 ascii2unicode(secret, secret_len, unicodePassword);
332 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
333 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
335 mppe_set_keys(rchallenge, PasswordHashHash);
339 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
342 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
344 SHA1_CTX sha1Context;
345 u_char unicodePassword[MAX_NT_PASSWORD * 2];
346 u_char PasswordHash[MD4_SIGNATURE_SIZE];
347 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
348 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
349 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
352 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
357 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
358 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
359 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
360 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
362 /* "This is the MPPE Master Key" */
364 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
365 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
366 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
367 /* "On the client side, this is the send key; "
368 "on the server side, it is the receive key." */
370 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
371 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
372 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
373 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
374 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
375 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
376 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
377 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
378 0x6b, 0x65, 0x79, 0x2e };
379 /* "On the client side, this is the receive key; "
380 "on the server side, it is the send key." */
382 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
383 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
384 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
385 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
386 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
387 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
388 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
389 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
390 0x6b, 0x65, 0x79, 0x2e };
393 /* Hash (x2) the Unicode version of the secret (== password). */
394 ascii2unicode(secret, secret_len, unicodePassword);
395 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
396 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
398 SHA1_Init(&sha1Context);
399 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
400 SHA1_Update(&sha1Context, NTResponse, 24);
401 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
402 SHA1_Final(MasterKey, &sha1Context);
411 SHA1_Init(&sha1Context);
412 SHA1_Update(&sha1Context, MasterKey, 16);
413 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
414 SHA1_Update(&sha1Context, s, 84);
415 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
416 SHA1_Final(Digest, &sha1Context);
418 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
427 SHA1_Init(&sha1Context);
428 SHA1_Update(&sha1Context, MasterKey, 16);
429 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
430 SHA1_Update(&sha1Context, s, 84);
431 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
432 SHA1_Final(Digest, &sha1Context);
434 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
441 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
442 MS_ChapResponse *response)
445 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
447 BZERO(response, sizeof(*response));
449 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
452 ChapMS_LANMan(rchallenge, secret, secret_len, response);
454 /* preferred method is set by option */
455 response->UseNT[0] = !ms_lanman;
457 response->UseNT[0] = 1;
460 cstate->resp_length = MS_CHAP_RESPONSE_LEN;
463 Set_Start_Key(rchallenge, secret, secret_len);
469 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
470 * is filled in. Call this way when generating a response.
471 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
472 * Call this way when verifying a response (or debugging).
473 * Do not call with PeerChallenge = response->PeerChallenge.
475 * response->PeerChallenge is then used for calculation of the
476 * Authenticator Response.
479 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
480 char *user, char *secret, int secret_len, MS_Chap2Response *response,
481 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
484 u_char *p = response->PeerChallenge;
487 BZERO(response, sizeof(*response));
489 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
491 for (i = 0; i < sizeof(response->PeerChallenge); i++)
492 *p++ = (u_char) (drand48() * 0xff);
494 BCOPY(PeerChallenge, response->PeerChallenge,
495 sizeof(response->PeerChallenge));
497 /* Generate the NT-Response */
498 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
499 secret, secret_len, response->NTResp);
501 /* Generate the Authenticator Response. */
502 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
503 response->PeerChallenge, rchallenge,
506 cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
509 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);