1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1997 Gabor Kincses <gabor@acm.org>
5 * 1997 - 2001 Brian Somers <brian@Awfulhak.org>
6 * based on work by Eric Rosenquist
7 * Strata Software Limited.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34 #include <ctype.h>
35 #ifdef __FreeBSD__
36 #include <openssl/des.h>
37 #include <sha.h>
38 #else
39 #include <sys/types.h>
40 #include <stdlib.h>
41 #ifdef __NetBSD__
42 #include <openssl/des.h>
43 #else
44 #include <des.h>
45 #endif
46 #include <openssl/sha.h>
47 #endif
48 #include <md4.h>
49 #include <string.h>
50
51 #include "chap_ms.h"
52
53 /*
54 * Documentation & specifications:
55 *
56 * MS-CHAP (CHAP80) rfc2433
57 * MS-CHAP-V2 (CHAP81) rfc2759
58 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt
59 */
60
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};
66
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};
72
73 /* unused, for documentation only */
74 /* only NTResp is filled in for FreeBSD */
75 struct MS_ChapResponse {
76 u_char LANManResp[24];
77 u_char NTResp[24];
78 u_char UseNT; /* If 1, ignore the LANMan response field */
79 };
80
81 static u_char
Get7Bits(u_char * input,int startBit)82 Get7Bits(u_char *input, int startBit)
83 {
84 register unsigned int word;
85
86 word = (unsigned)input[startBit / 8] << 8;
87 word |= (unsigned)input[startBit / 8 + 1];
88
89 word >>= 15 - (startBit % 8 + 7);
90
91 return word & 0xFE;
92 }
93
94 /* IN 56 bit DES key missing parity bits
95 OUT 64 bit DES key with parity bits added */
96 static void
MakeKey(u_char * key,u_char * des_key)97 MakeKey(u_char *key, u_char *des_key)
98 {
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);
107
108 des_set_odd_parity((des_cblock *)des_key);
109 }
110
111 static void /* IN 8 octets IN 7 octest OUT 8 octets */
DesEncrypt(u_char * clear,u_char * key,u_char * cipher)112 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
113 {
114 des_cblock des_key;
115 des_key_schedule key_schedule;
116
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);
120 }
121
122 static void /* IN 8 octets IN 16 octets OUT 24 octets */
ChallengeResponse(u_char * challenge,u_char * pwHash,u_char * response)123 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
124 {
125 char ZPasswordHash[21];
126
127 memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
128 memcpy(ZPasswordHash, pwHash, 16);
129
130 DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
131 DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
132 DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
133 }
134
135 void
NtPasswordHash(char * key,int keylen,char * hash)136 NtPasswordHash(char *key, int keylen, char *hash)
137 {
138 MD4_CTX MD4context;
139
140 MD4Init(&MD4context);
141 MD4Update(&MD4context, key, keylen);
142 MD4Final(hash, &MD4context);
143 }
144
145 void
HashNtPasswordHash(char * hash,char * hashhash)146 HashNtPasswordHash(char *hash, char *hashhash)
147 {
148 MD4_CTX MD4context;
149
150 MD4Init(&MD4context);
151 MD4Update(&MD4context, hash, 16);
152 MD4Final(hashhash, &MD4context);
153 }
154
155 static void
ChallengeHash(char * PeerChallenge,char * AuthenticatorChallenge,char * UserName,char * Challenge)156 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
157 char *UserName, char *Challenge)
158 {
159 SHA_CTX Context;
160 char Digest[SHA_DIGEST_LENGTH];
161 char *Name;
162
163 Name = strrchr(UserName, '\\');
164 if(NULL == Name)
165 Name = UserName;
166 else
167 Name++;
168
169 SHA1_Init(&Context);
170
171 SHA1_Update(&Context, PeerChallenge, 16);
172 SHA1_Update(&Context, AuthenticatorChallenge, 16);
173 SHA1_Update(&Context, Name, strlen(Name));
174
175 SHA1_Final(Digest, &Context);
176 memcpy(Challenge, Digest, 8);
177 }
178
179 void
GenerateNTResponse(char * AuthenticatorChallenge,char * PeerChallenge,char * UserName,char * Password,int PasswordLen,char * Response)180 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
181 char *UserName, char *Password,
182 int PasswordLen, char *Response)
183 {
184 char Challenge[8];
185 char PasswordHash[16];
186
187 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
188 NtPasswordHash(Password, PasswordLen, PasswordHash);
189 ChallengeResponse(Challenge, PasswordHash, Response);
190 }
191
192 #ifndef __FreeBSD__
193 #define LENGTH 20
194 static char *
SHA1_End(SHA_CTX * ctx,char * buf)195 SHA1_End(SHA_CTX *ctx, char *buf)
196 {
197 int i;
198 unsigned char digest[LENGTH];
199 static const char hex[]="0123456789abcdef";
200
201 if (!buf)
202 buf = malloc(2*LENGTH + 1);
203 if (!buf)
204 return 0;
205 SHA1_Final(digest, ctx);
206 for (i = 0; i < LENGTH; i++) {
207 buf[i+i] = hex[digest[i] >> 4];
208 buf[i+i+1] = hex[digest[i] & 0x0f];
209 }
210 buf[i+i] = '\0';
211 return buf;
212 }
213 #endif
214
215 void
GenerateAuthenticatorResponse(char * Password,int PasswordLen,char * NTResponse,char * PeerChallenge,char * AuthenticatorChallenge,char * UserName,char * AuthenticatorResponse)216 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
217 char *NTResponse, char *PeerChallenge,
218 char *AuthenticatorChallenge, char *UserName,
219 char *AuthenticatorResponse)
220 {
221 SHA_CTX Context;
222 char PasswordHash[16];
223 char PasswordHashHash[16];
224 char Challenge[8];
225 u_char Digest[SHA_DIGEST_LENGTH];
226 int i;
227
228 /*
229 * "Magic" constants used in response generation
230 */
231 char Magic1[39] =
232 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
233 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
234 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
235 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
236
237
238 char Magic2[41] =
239 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
240 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
241 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
242 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
243 0x6E};
244 /*
245 * Hash the password with MD4
246 */
247 NtPasswordHash(Password, PasswordLen, PasswordHash);
248 /*
249 * Now hash the hash
250 */
251 HashNtPasswordHash(PasswordHash, PasswordHashHash);
252
253 SHA1_Init(&Context);
254 SHA1_Update(&Context, PasswordHashHash, 16);
255 SHA1_Update(&Context, NTResponse, 24);
256 SHA1_Update(&Context, Magic1, 39);
257 SHA1_Final(Digest, &Context);
258 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
259 SHA1_Init(&Context);
260 SHA1_Update(&Context, Digest, 20);
261 SHA1_Update(&Context, Challenge, 8);
262 SHA1_Update(&Context, Magic2, 41);
263
264 /*
265 * Encode the value of 'Digest' as "S=" followed by
266 * 40 ASCII hexadecimal digits and return it in
267 * AuthenticatorResponse.
268 * For example,
269 * "S=0123456789ABCDEF0123456789ABCDEF01234567"
270 */
271 AuthenticatorResponse[0] = 'S';
272 AuthenticatorResponse[1] = '=';
273 SHA1_End(&Context, AuthenticatorResponse + 2);
274 for (i=2; i<42; i++)
275 AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
276
277 }
278
279 void
GetMasterKey(char * PasswordHashHash,char * NTResponse,char * MasterKey)280 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
281 {
282 char Digest[SHA_DIGEST_LENGTH];
283 SHA_CTX Context;
284 static char Magic1[27] =
285 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
286 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
287 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
288
289 SHA1_Init(&Context);
290 SHA1_Update(&Context, PasswordHashHash, 16);
291 SHA1_Update(&Context, NTResponse, 24);
292 SHA1_Update(&Context, Magic1, 27);
293 SHA1_Final(Digest, &Context);
294 memcpy(MasterKey, Digest, 16);
295 }
296
297 void
GetAsymetricStartKey(char * MasterKey,char * SessionKey,int SessionKeyLength,int IsSend,int IsServer)298 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
299 int IsSend, int IsServer)
300 {
301 char Digest[SHA_DIGEST_LENGTH];
302 SHA_CTX Context;
303 char *s;
304
305 static char Magic2[84] =
306 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
307 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
308 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
309 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
310 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
311 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
312 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
313 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
314 0x6b, 0x65, 0x79, 0x2e};
315
316 static char Magic3[84] =
317 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
318 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
319 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
320 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
321 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
322 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
323 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
324 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
325 0x6b, 0x65, 0x79, 0x2e};
326
327 if (IsSend) {
328 if (IsServer) {
329 s = Magic3;
330 } else {
331 s = Magic2;
332 }
333 } else {
334 if (IsServer) {
335 s = Magic2;
336 } else {
337 s = Magic3;
338 }
339 }
340
341 SHA1_Init(&Context);
342 SHA1_Update(&Context, MasterKey, 16);
343 SHA1_Update(&Context, SHA1_Pad1, 40);
344 SHA1_Update(&Context, s, 84);
345 SHA1_Update(&Context, SHA1_Pad2, 40);
346 SHA1_Final(Digest, &Context);
347
348 memcpy(SessionKey, Digest, SessionKeyLength);
349 }
350
351 void
GetNewKeyFromSHA(char * StartKey,char * SessionKey,long SessionKeyLength,char * InterimKey)352 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
353 char *InterimKey)
354 {
355 SHA_CTX Context;
356 char Digest[SHA_DIGEST_LENGTH];
357
358 SHA1_Init(&Context);
359 SHA1_Update(&Context, StartKey, SessionKeyLength);
360 SHA1_Update(&Context, SHA1_Pad1, 40);
361 SHA1_Update(&Context, SessionKey, SessionKeyLength);
362 SHA1_Update(&Context, SHA1_Pad2, 40);
363 SHA1_Final(Digest, &Context);
364
365 memcpy(InterimKey, Digest, SessionKeyLength);
366 }
367
368 #if 0
369 static void
370 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
371 int LengthOfDesiredKey)
372 {
373 SHA_CTX Context;
374 char Digest[SHA_DIGEST_LENGTH];
375
376 SHA1_Init(&Context);
377 SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
378 SHA1_Update(&Context, SHA1_Pad1, 40);
379 SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
380 SHA1_Update(&Context, SHA1_Pad2, 40);
381 SHA1_Final(Digest, &Context);
382
383 memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
384 }
385 #endif
386
387 /* passwordHash 16-bytes MD4 hashed password
388 challenge 8-bytes peer CHAP challenge
389 since passwordHash is in a 24-byte buffer, response is written in there */
390 void
mschap_NT(char * passwordHash,char * challenge)391 mschap_NT(char *passwordHash, char *challenge)
392 {
393 u_char response[24];
394
395 ChallengeResponse(challenge, passwordHash, response);
396 memcpy(passwordHash, response, 24);
397 passwordHash[24] = 1; /* NT-style response */
398 }
399
400 void
mschap_LANMan(char * digest,char * challenge,char * secret)401 mschap_LANMan(char *digest, char *challenge, char *secret)
402 {
403 static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */
404 char SECRET[14], *ptr, *end;
405 u_char hash[16];
406
407 end = SECRET + sizeof SECRET;
408 for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
409 *ptr = toupper(*secret);
410 if (ptr < end)
411 memset(ptr, '\0', end - ptr);
412
413 DesEncrypt(salt, SECRET, hash);
414 DesEncrypt(salt, SECRET + 7, hash + 8);
415
416 ChallengeResponse(challenge, hash, digest);
417 }
418