xref: /freebsd/usr.sbin/ppp/chap_ms.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*
2  * chap_ms.c - Microsoft MS-CHAP (NT only) compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5  * http://www.strataware.com/
6  *
7  * All rights reserved.
8  *
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.
17  *
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.
21  *
22  * $FreeBSD$
23  *
24  */
25 
26 #include <sys/types.h>
27 
28 #include <ctype.h>
29 #ifdef __FreeBSD__
30 #include <openssl/des.h>
31 #include <sha.h>
32 #else
33 #include <stdlib.h>
34 #include <des.h>
35 #include <openssl/sha.h>
36 #endif
37 #include <md4.h>
38 #include <string.h>
39 
40 #include "chap_ms.h"
41 
42 /*
43  * Documentation & specifications:
44  *
45  * MS-CHAP (CHAP80)	rfc2433
46  * MS-CHAP-V2 (CHAP81)	rfc2759
47  * MPPE key management	draft-ietf-pppext-mppe-keys-02.txt
48  */
49 
50 static char SHA1_Pad1[40] =
51   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
55 
56 static char SHA1_Pad2[40] =
57   {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
58    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
59    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
60    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
61 
62 /* unused, for documentation only */
63 /* only NTResp is filled in for FreeBSD */
64 struct MS_ChapResponse {
65     u_char LANManResp[24];
66     u_char NTResp[24];
67     u_char UseNT;	/* If 1, ignore the LANMan response field */
68 };
69 
70 static u_char
71 Get7Bits(u_char *input, int startBit)
72 {
73     register unsigned int	word;
74 
75     word  = (unsigned)input[startBit / 8] << 8;
76     word |= (unsigned)input[startBit / 8 + 1];
77 
78     word >>= 15 - (startBit % 8 + 7);
79 
80     return word & 0xFE;
81 }
82 
83 /* IN  56 bit DES key missing parity bits
84    OUT 64 bit DES key with parity bits added */
85 static void
86 MakeKey(u_char *key, u_char *des_key)
87 {
88     des_key[0] = Get7Bits(key,  0);
89     des_key[1] = Get7Bits(key,  7);
90     des_key[2] = Get7Bits(key, 14);
91     des_key[3] = Get7Bits(key, 21);
92     des_key[4] = Get7Bits(key, 28);
93     des_key[5] = Get7Bits(key, 35);
94     des_key[6] = Get7Bits(key, 42);
95     des_key[7] = Get7Bits(key, 49);
96 
97     des_set_odd_parity((des_cblock *)des_key);
98 }
99 
100 static void /* IN 8 octets IN 7 octest OUT 8 octets */
101 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
102 {
103     des_cblock		des_key;
104     des_key_schedule	key_schedule;
105 
106     MakeKey(key, des_key);
107     des_set_key(&des_key, key_schedule);
108     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
109 }
110 
111 static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
112 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
113 {
114     char    ZPasswordHash[21];
115 
116     memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
117     memcpy(ZPasswordHash, pwHash, 16);
118 
119     DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
120     DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
121     DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
122 }
123 
124 void
125 NtPasswordHash(char *key, int keylen, char *hash)
126 {
127   MD4_CTX MD4context;
128 
129   MD4Init(&MD4context);
130   MD4Update(&MD4context, key, keylen);
131   MD4Final(hash, &MD4context);
132 }
133 
134 void
135 HashNtPasswordHash(char *hash, char *hashhash)
136 {
137   MD4_CTX MD4context;
138 
139   MD4Init(&MD4context);
140   MD4Update(&MD4context, hash, 16);
141   MD4Final(hashhash, &MD4context);
142 }
143 
144 void
145 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
146               char *UserName, int UserNameLen, char *Challenge)
147 {
148   SHA_CTX Context;
149   char Digest[SHA_DIGEST_LENGTH];
150   char *Name;
151 
152   Name = strrchr(UserName, '\\');
153   if(NULL == Name)
154     Name = UserName;
155   else
156     Name++;
157 
158   SHA1_Init(&Context);
159 
160   SHA1_Update(&Context, PeerChallenge, 16);
161   SHA1_Update(&Context, AuthenticatorChallenge, 16);
162   SHA1_Update(&Context, UserName, UserNameLen);
163 
164   SHA1_Final(Digest, &Context);
165   memcpy(Challenge, Digest, 8);
166 }
167 
168 void
169 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
170                    char *UserName, int UserNameLen, char *Password,
171                    int PasswordLen, char *Response)
172 {
173   char Challenge[8];
174   char PasswordHash[16];
175 
176   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
177                 Challenge);
178   NtPasswordHash(Password, PasswordLen, PasswordHash);
179   ChallengeResponse(Challenge, PasswordHash, Response);
180 }
181 
182 #ifndef __FreeBSD__
183 #define LENGTH 20
184 char *
185 SHA1_End(SHA_CTX *ctx, char *buf)
186 {
187     int i;
188     unsigned char digest[LENGTH];
189     static const char hex[]="0123456789abcdef";
190 
191     if (!buf)
192         buf = malloc(2*LENGTH + 1);
193     if (!buf)
194         return 0;
195     SHA1_Final(digest, ctx);
196     for (i = 0; i < LENGTH; i++) {
197         buf[i+i] = hex[digest[i] >> 4];
198         buf[i+i+1] = hex[digest[i] & 0x0f];
199     }
200     buf[i+i] = '\0';
201     return buf;
202 }
203 #endif
204 
205 void
206 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
207                               char *NTResponse, char *PeerChallenge,
208                               char *AuthenticatorChallenge, char *UserName,
209                               int UserNameLen, char *AuthenticatorResponse)
210 {
211   SHA_CTX Context;
212   char PasswordHash[16];
213   char PasswordHashHash[16];
214   char Challenge[8];
215   u_char Digest[SHA_DIGEST_LENGTH];
216   int i;
217 
218       /*
219        * "Magic" constants used in response generation
220        */
221   char Magic1[39] =
222          {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
223           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
224           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
225           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
226 
227 
228   char Magic2[41] =
229          {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
230           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
231           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
232           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
233           0x6E};
234       /*
235        * Hash the password with MD4
236        */
237   NtPasswordHash(Password, PasswordLen, PasswordHash);
238       /*
239        * Now hash the hash
240        */
241   HashNtPasswordHash(PasswordHash, PasswordHashHash);
242 
243   SHA1_Init(&Context);
244   SHA1_Update(&Context, PasswordHashHash, 16);
245   SHA1_Update(&Context, NTResponse, 24);
246   SHA1_Update(&Context, Magic1, 39);
247   SHA1_Final(Digest, &Context);
248   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
249                 Challenge);
250   SHA1_Init(&Context);
251   SHA1_Update(&Context, Digest, 20);
252   SHA1_Update(&Context, Challenge, 8);
253   SHA1_Update(&Context, Magic2, 41);
254 
255       /*
256        * Encode the value of 'Digest' as "S=" followed by
257        * 40 ASCII hexadecimal digits and return it in
258        * AuthenticatorResponse.
259        * For example,
260        *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
261        */
262   AuthenticatorResponse[0] = 'S';
263   AuthenticatorResponse[1] = '=';
264   SHA1_End(&Context, AuthenticatorResponse + 2);
265   for (i=2; i<42; i++)
266     AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
267 
268 }
269 
270 void
271 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
272 {
273   char Digest[SHA_DIGEST_LENGTH];
274   SHA_CTX Context;
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};
279 
280   SHA1_Init(&Context);
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);
286 }
287 
288 void
289 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
290                      int IsSend, int IsServer)
291 {
292   char Digest[SHA_DIGEST_LENGTH];
293   SHA_CTX Context;
294   char *s;
295 
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};
306 
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};
317 
318   if (IsSend) {
319      if (IsServer) {
320         s = Magic3;
321      } else {
322         s = Magic2;
323      }
324   } else {
325      if (IsServer) {
326         s = Magic2;
327      } else {
328         s = Magic3;
329      }
330   }
331 
332   SHA1_Init(&Context);
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);
338 
339   memcpy(SessionKey, Digest, SessionKeyLength);
340 }
341 
342 void
343 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
344                  char *InterimKey)
345 {
346   SHA_CTX Context;
347   char Digest[SHA_DIGEST_LENGTH];
348 
349   SHA1_Init(&Context);
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);
355 
356   memcpy(InterimKey, Digest, SessionKeyLength);
357 }
358 
359 #if 0
360 static void
361 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
362         int LengthOfDesiredKey)
363 {
364   SHA_CTX Context;
365   char Digest[SHA_DIGEST_LENGTH];
366 
367   SHA1_Init(&Context);
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);
373 
374   memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
375 }
376 #endif
377 
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 */
381 void
382 mschap_NT(char *passwordHash, char *challenge)
383 {
384     u_char response[24];
385 
386     ChallengeResponse(challenge, passwordHash, response);
387     memcpy(passwordHash, response, 24);
388     passwordHash[24] = 1;		/* NT-style response */
389 }
390 
391 void
392 mschap_LANMan(char *digest, char *challenge, char *secret)
393 {
394   static u_char salt[] = "KGS!@#$%";	/* RASAPI32.dll */
395   char SECRET[14], *ptr, *end;
396   u_char hash[16];
397 
398   end = SECRET + sizeof SECRET;
399   for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
400     *ptr = toupper(*secret);
401   if (ptr < end)
402     memset(ptr, '\0', end - ptr);
403 
404   DesEncrypt(salt, SECRET, hash);
405   DesEncrypt(salt, SECRET + 7, hash + 8);
406 
407   ChallengeResponse(challenge, hash, digest);
408 }
409