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