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 $
34 #include <sys/types.h>
35 #include <openssl/des.h>
39 #include <sys/types.h>
42 #include <openssl/des.h>
46 #include <openssl/sha.h>
54 * Documentation & specifications:
56 * MS-CHAP (CHAP80) rfc2433
57 * MS-CHAP-V2 (CHAP81) rfc2759
58 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt
61 static char SHA1_Pad1
[40] =
62 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
67 static char SHA1_Pad2
[40] =
68 {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
69 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
70 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
71 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
73 /* unused, for documentation only */
74 /* only NTResp is filled in for FreeBSD */
75 struct MS_ChapResponse
{
76 u_char LANManResp
[24];
78 u_char UseNT
; /* If 1, ignore the LANMan response field */
82 Get7Bits(u_char
*input
, int startBit
)
86 word
= (unsigned)input
[startBit
/ 8] << 8;
87 word
|= (unsigned)input
[startBit
/ 8 + 1];
89 word
>>= 15 - (startBit
% 8 + 7);
94 /* IN 56 bit DES key missing parity bits
95 OUT 64 bit DES key with parity bits added */
97 MakeKey(u_char
*key
, u_char
*des_key
)
99 des_key
[0] = Get7Bits(key
, 0);
100 des_key
[1] = Get7Bits(key
, 7);
101 des_key
[2] = Get7Bits(key
, 14);
102 des_key
[3] = Get7Bits(key
, 21);
103 des_key
[4] = Get7Bits(key
, 28);
104 des_key
[5] = Get7Bits(key
, 35);
105 des_key
[6] = Get7Bits(key
, 42);
106 des_key
[7] = Get7Bits(key
, 49);
108 DES_set_odd_parity((DES_cblock
*)des_key
);
111 static void /* IN 8 octets IN 7 octest OUT 8 octets */
112 DesEncrypt(u_char
*clear
, u_char
*key
, u_char
*cipher
)
115 DES_key_schedule key_schedule
;
117 MakeKey(key
, des_key
);
118 DES_set_key(&des_key
, &key_schedule
);
119 DES_ecb_encrypt((DES_cblock
*)clear
, (DES_cblock
*)cipher
, &key_schedule
, 1);
122 static void /* IN 8 octets IN 16 octets OUT 24 octets */
123 ChallengeResponse(u_char
*challenge
, u_char
*pwHash
, u_char
*response
)
125 char ZPasswordHash
[21];
127 memset(ZPasswordHash
, '\0', sizeof ZPasswordHash
);
128 memcpy(ZPasswordHash
, pwHash
, 16);
130 DesEncrypt(challenge
, ZPasswordHash
+ 0, response
+ 0);
131 DesEncrypt(challenge
, ZPasswordHash
+ 7, response
+ 8);
132 DesEncrypt(challenge
, ZPasswordHash
+ 14, response
+ 16);
136 NtPasswordHash(char *key
, int keylen
, char *hash
)
140 MD4Init(&MD4context
);
141 MD4Update(&MD4context
, key
, keylen
);
142 MD4Final(hash
, &MD4context
);
146 HashNtPasswordHash(char *hash
, char *hashhash
)
150 MD4Init(&MD4context
);
151 MD4Update(&MD4context
, hash
, 16);
152 MD4Final(hashhash
, &MD4context
);
156 ChallengeHash(char *PeerChallenge
, char *AuthenticatorChallenge
,
157 char *UserName
, char *Challenge
)
160 char Digest
[SHA_DIGEST_LENGTH
];
163 Name
= strrchr(UserName
, '\\');
171 SHA1_Update(&Context
, PeerChallenge
, 16);
172 SHA1_Update(&Context
, AuthenticatorChallenge
, 16);
173 SHA1_Update(&Context
, Name
, strlen(Name
));
175 SHA1_Final(Digest
, &Context
);
176 memcpy(Challenge
, Digest
, 8);
180 GenerateNTResponse(char *AuthenticatorChallenge
, char *PeerChallenge
,
181 char *UserName
, char *Password
,
182 int PasswordLen
, char *Response
)
185 char PasswordHash
[16];
187 ChallengeHash(PeerChallenge
, AuthenticatorChallenge
, UserName
, Challenge
);
188 NtPasswordHash(Password
, PasswordLen
, PasswordHash
);
189 ChallengeResponse(Challenge
, PasswordHash
, Response
);
194 SHA1_End(SHA_CTX
*ctx
, char *buf
)
197 unsigned char digest
[LENGTH
];
198 static const char hex
[]="0123456789abcdef";
201 buf
= malloc(2*LENGTH
+ 1);
204 SHA1_Final(digest
, ctx
);
205 for (i
= 0; i
< LENGTH
; i
++) {
206 buf
[i
+i
] = hex
[digest
[i
] >> 4];
207 buf
[i
+i
+1] = hex
[digest
[i
] & 0x0f];
214 GenerateAuthenticatorResponse(char *Password
, int PasswordLen
,
215 char *NTResponse
, char *PeerChallenge
,
216 char *AuthenticatorChallenge
, char *UserName
,
217 char *AuthenticatorResponse
)
220 char PasswordHash
[16];
221 char PasswordHashHash
[16];
223 u_char Digest
[SHA_DIGEST_LENGTH
];
227 * "Magic" constants used in response generation
230 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
231 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
232 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
233 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
237 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
238 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
239 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
240 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
243 * Hash the password with MD4
245 NtPasswordHash(Password
, PasswordLen
, PasswordHash
);
249 HashNtPasswordHash(PasswordHash
, PasswordHashHash
);
252 SHA1_Update(&Context
, PasswordHashHash
, 16);
253 SHA1_Update(&Context
, NTResponse
, 24);
254 SHA1_Update(&Context
, Magic1
, 39);
255 SHA1_Final(Digest
, &Context
);
256 ChallengeHash(PeerChallenge
, AuthenticatorChallenge
, UserName
, Challenge
);
258 SHA1_Update(&Context
, Digest
, 20);
259 SHA1_Update(&Context
, Challenge
, 8);
260 SHA1_Update(&Context
, Magic2
, 41);
263 * Encode the value of 'Digest' as "S=" followed by
264 * 40 ASCII hexadecimal digits and return it in
265 * AuthenticatorResponse.
267 * "S=0123456789ABCDEF0123456789ABCDEF01234567"
269 AuthenticatorResponse
[0] = 'S';
270 AuthenticatorResponse
[1] = '=';
271 SHA1_End(&Context
, AuthenticatorResponse
+ 2);
273 AuthenticatorResponse
[i
] = toupper(AuthenticatorResponse
[i
]);
278 GetMasterKey(char *PasswordHashHash
, char *NTResponse
, char *MasterKey
)
280 char Digest
[SHA_DIGEST_LENGTH
];
282 static char Magic1
[27] =
283 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
284 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
285 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
288 SHA1_Update(&Context
, PasswordHashHash
, 16);
289 SHA1_Update(&Context
, NTResponse
, 24);
290 SHA1_Update(&Context
, Magic1
, 27);
291 SHA1_Final(Digest
, &Context
);
292 memcpy(MasterKey
, Digest
, 16);
296 GetAsymetricStartKey(char *MasterKey
, char *SessionKey
, int SessionKeyLength
,
297 int IsSend
, int IsServer
)
299 char Digest
[SHA_DIGEST_LENGTH
];
303 static char Magic2
[84] =
304 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
305 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
306 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
307 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
308 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
309 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
310 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
311 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
312 0x6b, 0x65, 0x79, 0x2e};
314 static char Magic3
[84] =
315 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
316 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
317 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
318 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
319 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
320 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
321 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
322 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
323 0x6b, 0x65, 0x79, 0x2e};
340 SHA1_Update(&Context
, MasterKey
, 16);
341 SHA1_Update(&Context
, SHA1_Pad1
, 40);
342 SHA1_Update(&Context
, s
, 84);
343 SHA1_Update(&Context
, SHA1_Pad2
, 40);
344 SHA1_Final(Digest
, &Context
);
346 memcpy(SessionKey
, Digest
, SessionKeyLength
);
350 GetNewKeyFromSHA(char *StartKey
, char *SessionKey
, long SessionKeyLength
,
354 char Digest
[SHA_DIGEST_LENGTH
];
357 SHA1_Update(&Context
, StartKey
, SessionKeyLength
);
358 SHA1_Update(&Context
, SHA1_Pad1
, 40);
359 SHA1_Update(&Context
, SessionKey
, SessionKeyLength
);
360 SHA1_Update(&Context
, SHA1_Pad2
, 40);
361 SHA1_Final(Digest
, &Context
);
363 memcpy(InterimKey
, Digest
, SessionKeyLength
);
368 Get_Key(char *InitialSessionKey
, char *CurrentSessionKey
,
369 int LengthOfDesiredKey
)
372 char Digest
[SHA_DIGEST_LENGTH
];
375 SHA1_Update(&Context
, InitialSessionKey
, LengthOfDesiredKey
);
376 SHA1_Update(&Context
, SHA1_Pad1
, 40);
377 SHA1_Update(&Context
, CurrentSessionKey
, LengthOfDesiredKey
);
378 SHA1_Update(&Context
, SHA1_Pad2
, 40);
379 SHA1_Final(Digest
, &Context
);
381 memcpy(CurrentSessionKey
, Digest
, LengthOfDesiredKey
);
385 /* passwordHash 16-bytes MD4 hashed password
386 challenge 8-bytes peer CHAP challenge
387 since passwordHash is in a 24-byte buffer, response is written in there */
389 mschap_NT(char *passwordHash
, char *challenge
)
393 ChallengeResponse(challenge
, passwordHash
, response
);
394 memcpy(passwordHash
, response
, 24);
395 passwordHash
[24] = 1; /* NT-style response */
399 mschap_LANMan(char *digest
, char *challenge
, char *secret
)
401 static u_char salt
[] = "KGS!@#$%"; /* RASAPI32.dll */
402 char SECRET
[14], *ptr
, *end
;
405 end
= SECRET
+ sizeof SECRET
;
406 for (ptr
= SECRET
; *secret
&& ptr
< end
; ptr
++, secret
++)
407 *ptr
= toupper(*secret
);
409 memset(ptr
, '\0', end
- ptr
);
411 DesEncrypt(salt
, SECRET
, hash
);
412 DesEncrypt(salt
, SECRET
+ 7, hash
+ 8);
414 ChallengeResponse(challenge
, hash
, digest
);