xref: /freebsd/usr.sbin/ppp/chap_ms.c (revision 51a9219f5780e61e1437d25220bf8750d9df7f8b)
1 /*-
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.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <ctype.h>
33 #ifdef __FreeBSD__
34 #include <openssl/des.h>
35 #include <sha.h>
36 #else
37 #include <sys/types.h>
38 #include <stdlib.h>
39 #ifdef __NetBSD__
40 #include <openssl/des.h>
41 #else
42 #include <des.h>
43 #endif
44 #include <openssl/sha.h>
45 #endif
46 #include <md4.h>
47 #include <string.h>
48 
49 #include "chap_ms.h"
50 
51 /*
52  * Documentation & specifications:
53  *
54  * MS-CHAP (CHAP80)	rfc2433
55  * MS-CHAP-V2 (CHAP81)	rfc2759
56  * MPPE key management	draft-ietf-pppext-mppe-keys-02.txt
57  */
58 
59 static char SHA1_Pad1[40] =
60   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
64 
65 static char SHA1_Pad2[40] =
66   {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
67    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
68    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
69    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
70 
71 /* unused, for documentation only */
72 /* only NTResp is filled in for FreeBSD */
73 struct MS_ChapResponse {
74     u_char LANManResp[24];
75     u_char NTResp[24];
76     u_char UseNT;	/* If 1, ignore the LANMan response field */
77 };
78 
79 static u_char
80 Get7Bits(u_char *input, int startBit)
81 {
82     register unsigned int	word;
83 
84     word  = (unsigned)input[startBit / 8] << 8;
85     word |= (unsigned)input[startBit / 8 + 1];
86 
87     word >>= 15 - (startBit % 8 + 7);
88 
89     return word & 0xFE;
90 }
91 
92 /* IN  56 bit DES key missing parity bits
93    OUT 64 bit DES key with parity bits added */
94 static void
95 MakeKey(u_char *key, u_char *des_key)
96 {
97     des_key[0] = Get7Bits(key,  0);
98     des_key[1] = Get7Bits(key,  7);
99     des_key[2] = Get7Bits(key, 14);
100     des_key[3] = Get7Bits(key, 21);
101     des_key[4] = Get7Bits(key, 28);
102     des_key[5] = Get7Bits(key, 35);
103     des_key[6] = Get7Bits(key, 42);
104     des_key[7] = Get7Bits(key, 49);
105 
106     des_set_odd_parity((des_cblock *)des_key);
107 }
108 
109 static void /* IN 8 octets IN 7 octest OUT 8 octets */
110 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
111 {
112     des_cblock		des_key;
113     des_key_schedule	key_schedule;
114 
115     MakeKey(key, des_key);
116     des_set_key(&des_key, key_schedule);
117     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
118 }
119 
120 static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
121 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
122 {
123     char    ZPasswordHash[21];
124 
125     memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
126     memcpy(ZPasswordHash, pwHash, 16);
127 
128     DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
129     DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
130     DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
131 }
132 
133 void
134 NtPasswordHash(char *key, int keylen, char *hash)
135 {
136   MD4_CTX MD4context;
137 
138   MD4Init(&MD4context);
139   MD4Update(&MD4context, key, keylen);
140   MD4Final(hash, &MD4context);
141 }
142 
143 void
144 HashNtPasswordHash(char *hash, char *hashhash)
145 {
146   MD4_CTX MD4context;
147 
148   MD4Init(&MD4context);
149   MD4Update(&MD4context, hash, 16);
150   MD4Final(hashhash, &MD4context);
151 }
152 
153 void
154 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
155               char *UserName, int UserNameLen, char *Challenge)
156 {
157   SHA_CTX Context;
158   char Digest[SHA_DIGEST_LENGTH];
159   char *Name;
160 
161   Name = strrchr(UserName, '\\');
162   if(NULL == Name)
163     Name = UserName;
164   else
165     Name++;
166 
167   SHA1_Init(&Context);
168 
169   SHA1_Update(&Context, PeerChallenge, 16);
170   SHA1_Update(&Context, AuthenticatorChallenge, 16);
171   SHA1_Update(&Context, Name, strlen(Name));
172 
173   SHA1_Final(Digest, &Context);
174   memcpy(Challenge, Digest, 8);
175 }
176 
177 void
178 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
179                    char *UserName, int UserNameLen, char *Password,
180                    int PasswordLen, char *Response)
181 {
182   char Challenge[8];
183   char PasswordHash[16];
184 
185   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
186                 Challenge);
187   NtPasswordHash(Password, PasswordLen, PasswordHash);
188   ChallengeResponse(Challenge, PasswordHash, Response);
189 }
190 
191 #ifndef __FreeBSD__
192 #define LENGTH 20
193 static char *
194 SHA1_End(SHA_CTX *ctx, char *buf)
195 {
196     int i;
197     unsigned char digest[LENGTH];
198     static const char hex[]="0123456789abcdef";
199 
200     if (!buf)
201         buf = malloc(2*LENGTH + 1);
202     if (!buf)
203         return 0;
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];
208     }
209     buf[i+i] = '\0';
210     return buf;
211 }
212 #endif
213 
214 void
215 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
216                               char *NTResponse, char *PeerChallenge,
217                               char *AuthenticatorChallenge, char *UserName,
218                               int UserNameLen, char *AuthenticatorResponse)
219 {
220   SHA_CTX Context;
221   char PasswordHash[16];
222   char PasswordHashHash[16];
223   char Challenge[8];
224   u_char Digest[SHA_DIGEST_LENGTH];
225   int i;
226 
227       /*
228        * "Magic" constants used in response generation
229        */
230   char Magic1[39] =
231          {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
232           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
233           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
234           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
235 
236 
237   char Magic2[41] =
238          {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
239           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
240           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
241           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
242           0x6E};
243       /*
244        * Hash the password with MD4
245        */
246   NtPasswordHash(Password, PasswordLen, PasswordHash);
247       /*
248        * Now hash the hash
249        */
250   HashNtPasswordHash(PasswordHash, PasswordHashHash);
251 
252   SHA1_Init(&Context);
253   SHA1_Update(&Context, PasswordHashHash, 16);
254   SHA1_Update(&Context, NTResponse, 24);
255   SHA1_Update(&Context, Magic1, 39);
256   SHA1_Final(Digest, &Context);
257   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
258                 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
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
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
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
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
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