2 * Copyright (c) 1997 Gabor Kincses <gabor@acm.org>
3 * 1997 - 2001 Brian Somers <brian@Awfulhak.org>
4 * based on work by Eric Rosenquist
5 * Strata Software Limited.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * 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 the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/usr.sbin/ppp/chap_ms.c,v 1.9.2.6 2002/09/01 02:12:23 brian Exp $
33 #include <sys/types.h>
35 #if defined(__DragonFly__) || defined(__NetBSD__)
36 #include <openssl/des.h>
40 #include <openssl/sha.h>
41 #include <openssl/md4.h>
47 * Documentation & specifications:
49 * MS-CHAP (CHAP80) rfc2433
50 * MS-CHAP-V2 (CHAP81) rfc2759
51 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt
54 static char SHA1_Pad1[40] =
55 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
60 static char SHA1_Pad2[40] =
61 {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
62 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
63 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
64 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
66 /* unused, for documentation only */
67 /* only NTResp is filled in for FreeBSD */
68 struct MS_ChapResponse {
69 u_char LANManResp[24];
71 u_char UseNT; /* If 1, ignore the LANMan response field */
75 Get7Bits(u_char *input, int startBit)
79 word = (unsigned)input[startBit / 8] << 8;
80 word |= (unsigned)input[startBit / 8 + 1];
82 word >>= 15 - (startBit % 8 + 7);
87 /* IN 56 bit DES key missing parity bits
88 OUT 64 bit DES key with parity bits added */
90 MakeKey(u_char *key, u_char *des_key)
92 des_key[0] = Get7Bits(key, 0);
93 des_key[1] = Get7Bits(key, 7);
94 des_key[2] = Get7Bits(key, 14);
95 des_key[3] = Get7Bits(key, 21);
96 des_key[4] = Get7Bits(key, 28);
97 des_key[5] = Get7Bits(key, 35);
98 des_key[6] = Get7Bits(key, 42);
99 des_key[7] = Get7Bits(key, 49);
101 DES_set_odd_parity((DES_cblock *)des_key);
104 static void /* IN 8 octets IN 7 octest OUT 8 octets */
105 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
108 DES_key_schedule key_schedule;
110 MakeKey(key, des_key);
111 DES_set_key(&des_key, &key_schedule);
112 DES_ecb_encrypt((DES_cblock *)clear, (DES_cblock *)cipher, &key_schedule, 1);
115 static void /* IN 8 octets IN 16 octets OUT 24 octets */
116 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
118 char ZPasswordHash[21];
120 memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
121 memcpy(ZPasswordHash, pwHash, 16);
123 DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
124 DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
125 DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
129 NtPasswordHash(char *key, int keylen, char *hash)
133 MD4_Init(&MD4context);
134 MD4_Update(&MD4context, key, keylen);
135 MD4_Final(hash, &MD4context);
139 HashNtPasswordHash(char *hash, char *hashhash)
143 MD4_Init(&MD4context);
144 MD4_Update(&MD4context, hash, 16);
145 MD4_Final(hashhash, &MD4context);
149 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
150 char *UserName, char *Challenge)
153 char Digest[SHA_DIGEST_LENGTH];
156 Name = strrchr(UserName, '\\');
164 SHA1_Update(&Context, PeerChallenge, 16);
165 SHA1_Update(&Context, AuthenticatorChallenge, 16);
166 SHA1_Update(&Context, Name, strlen(Name));
168 SHA1_Final(Digest, &Context);
169 memcpy(Challenge, Digest, 8);
173 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
174 char *UserName, char *Password,
175 int PasswordLen, char *Response)
178 char PasswordHash[16];
180 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
181 NtPasswordHash(Password, PasswordLen, PasswordHash);
182 ChallengeResponse(Challenge, PasswordHash, Response);
187 SHA1_End(SHA_CTX *ctx, char *buf)
190 unsigned char digest[LENGTH];
191 static const char hex[]="0123456789abcdef";
194 buf = malloc(2*LENGTH + 1);
197 SHA1_Final(digest, ctx);
198 for (i = 0; i < LENGTH; i++) {
199 buf[i+i] = hex[digest[i] >> 4];
200 buf[i+i+1] = hex[digest[i] & 0x0f];
207 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
208 char *NTResponse, char *PeerChallenge,
209 char *AuthenticatorChallenge, char *UserName,
210 char *AuthenticatorResponse)
213 char PasswordHash[16];
214 char PasswordHashHash[16];
216 u_char Digest[SHA_DIGEST_LENGTH];
220 * "Magic" constants used in response generation
223 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
224 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
225 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
226 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
230 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
231 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
232 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
233 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
236 * Hash the password with MD4
238 NtPasswordHash(Password, PasswordLen, PasswordHash);
242 HashNtPasswordHash(PasswordHash, PasswordHashHash);
245 SHA1_Update(&Context, PasswordHashHash, 16);
246 SHA1_Update(&Context, NTResponse, 24);
247 SHA1_Update(&Context, Magic1, 39);
248 SHA1_Final(Digest, &Context);
249 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
251 SHA1_Update(&Context, Digest, 20);
252 SHA1_Update(&Context, Challenge, 8);
253 SHA1_Update(&Context, Magic2, 41);
256 * Encode the value of 'Digest' as "S=" followed by
257 * 40 ASCII hexadecimal digits and return it in
258 * AuthenticatorResponse.
260 * "S=0123456789ABCDEF0123456789ABCDEF01234567"
262 AuthenticatorResponse[0] = 'S';
263 AuthenticatorResponse[1] = '=';
264 SHA1_End(&Context, AuthenticatorResponse + 2);
266 AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
271 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
273 char Digest[SHA_DIGEST_LENGTH];
275 static char Magic1[27] =
276 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
277 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
278 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
281 SHA1_Update(&Context, PasswordHashHash, 16);
282 SHA1_Update(&Context, NTResponse, 24);
283 SHA1_Update(&Context, Magic1, 27);
284 SHA1_Final(Digest, &Context);
285 memcpy(MasterKey, Digest, 16);
289 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
290 int IsSend, int IsServer)
292 char Digest[SHA_DIGEST_LENGTH];
296 static char Magic2[84] =
297 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
298 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
299 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
300 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
301 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
302 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
303 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
304 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
305 0x6b, 0x65, 0x79, 0x2e};
307 static char Magic3[84] =
308 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
309 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
310 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
311 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
312 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
313 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
314 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
315 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
316 0x6b, 0x65, 0x79, 0x2e};
333 SHA1_Update(&Context, MasterKey, 16);
334 SHA1_Update(&Context, SHA1_Pad1, 40);
335 SHA1_Update(&Context, s, 84);
336 SHA1_Update(&Context, SHA1_Pad2, 40);
337 SHA1_Final(Digest, &Context);
339 memcpy(SessionKey, Digest, SessionKeyLength);
343 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
347 char Digest[SHA_DIGEST_LENGTH];
350 SHA1_Update(&Context, StartKey, SessionKeyLength);
351 SHA1_Update(&Context, SHA1_Pad1, 40);
352 SHA1_Update(&Context, SessionKey, SessionKeyLength);
353 SHA1_Update(&Context, SHA1_Pad2, 40);
354 SHA1_Final(Digest, &Context);
356 memcpy(InterimKey, Digest, SessionKeyLength);
361 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
362 int LengthOfDesiredKey)
365 char Digest[SHA_DIGEST_LENGTH];
368 SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
369 SHA1_Update(&Context, SHA1_Pad1, 40);
370 SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
371 SHA1_Update(&Context, SHA1_Pad2, 40);
372 SHA1_Final(Digest, &Context);
374 memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
378 /* passwordHash 16-bytes MD4 hashed password
379 challenge 8-bytes peer CHAP challenge
380 since passwordHash is in a 24-byte buffer, response is written in there */
382 mschap_NT(char *passwordHash, char *challenge)
386 ChallengeResponse(challenge, passwordHash, response);
387 memcpy(passwordHash, response, 24);
388 passwordHash[24] = 1; /* NT-style response */
392 mschap_LANMan(char *digest, char *challenge, char *secret)
394 static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */
395 char SECRET[14], *ptr, *end;
398 end = SECRET + sizeof SECRET;
399 for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
400 *ptr = toupper(*secret);
402 memset(ptr, '\0', end - ptr);
404 DesEncrypt(salt, SECRET, hash);
405 DesEncrypt(salt, SECRET + 7, hash + 8);
407 ChallengeResponse(challenge, hash, digest);