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: releng/11.0/usr.sbin/ppp/chap_ms.c 134789 2004-09-05 01:46:52Z brian $
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
59static 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
65static 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 */
73struct 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
79static u_char
80Get7Bits(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 */
94static void
95MakeKey(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
109static void /* IN 8 octets IN 7 octest OUT 8 octets */
110DesEncrypt(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
120static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
121ChallengeResponse(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
133void
134NtPasswordHash(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
143void
144HashNtPasswordHash(char *hash, char *hashhash)
145{
146  MD4_CTX MD4context;
147
148  MD4Init(&MD4context);
149  MD4Update(&MD4context, hash, 16);
150  MD4Final(hashhash, &MD4context);
151}
152
153static void
154ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
155              char *UserName, 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
177void
178GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
179                   char *UserName, char *Password,
180                   int PasswordLen, char *Response)
181{
182  char Challenge[8];
183  char PasswordHash[16];
184
185  ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
186  NtPasswordHash(Password, PasswordLen, PasswordHash);
187  ChallengeResponse(Challenge, PasswordHash, Response);
188}
189
190#ifndef __FreeBSD__
191#define LENGTH 20
192static char *
193SHA1_End(SHA_CTX *ctx, char *buf)
194{
195    int i;
196    unsigned char digest[LENGTH];
197    static const char hex[]="0123456789abcdef";
198
199    if (!buf)
200        buf = malloc(2*LENGTH + 1);
201    if (!buf)
202        return 0;
203    SHA1_Final(digest, ctx);
204    for (i = 0; i < LENGTH; i++) {
205        buf[i+i] = hex[digest[i] >> 4];
206        buf[i+i+1] = hex[digest[i] & 0x0f];
207    }
208    buf[i+i] = '\0';
209    return buf;
210}
211#endif
212
213void
214GenerateAuthenticatorResponse(char *Password, int PasswordLen,
215                              char *NTResponse, char *PeerChallenge,
216                              char *AuthenticatorChallenge, char *UserName,
217                              char *AuthenticatorResponse)
218{
219  SHA_CTX Context;
220  char PasswordHash[16];
221  char PasswordHashHash[16];
222  char Challenge[8];
223  u_char Digest[SHA_DIGEST_LENGTH];
224  int i;
225
226      /*
227       * "Magic" constants used in response generation
228       */
229  char Magic1[39] =
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};
234
235
236  char Magic2[41] =
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,
241          0x6E};
242      /*
243       * Hash the password with MD4
244       */
245  NtPasswordHash(Password, PasswordLen, PasswordHash);
246      /*
247       * Now hash the hash
248       */
249  HashNtPasswordHash(PasswordHash, PasswordHashHash);
250
251  SHA1_Init(&Context);
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);
257  SHA1_Init(&Context);
258  SHA1_Update(&Context, Digest, 20);
259  SHA1_Update(&Context, Challenge, 8);
260  SHA1_Update(&Context, Magic2, 41);
261
262      /*
263       * Encode the value of 'Digest' as "S=" followed by
264       * 40 ASCII hexadecimal digits and return it in
265       * AuthenticatorResponse.
266       * For example,
267       *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
268       */
269  AuthenticatorResponse[0] = 'S';
270  AuthenticatorResponse[1] = '=';
271  SHA1_End(&Context, AuthenticatorResponse + 2);
272  for (i=2; i<42; i++)
273    AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
274
275}
276
277void
278GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
279{
280  char Digest[SHA_DIGEST_LENGTH];
281  SHA_CTX Context;
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};
286
287  SHA1_Init(&Context);
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);
293}
294
295void
296GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
297                     int IsSend, int IsServer)
298{
299  char Digest[SHA_DIGEST_LENGTH];
300  SHA_CTX Context;
301  char *s;
302
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};
313
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};
324
325  if (IsSend) {
326     if (IsServer) {
327        s = Magic3;
328     } else {
329        s = Magic2;
330     }
331  } else {
332     if (IsServer) {
333        s = Magic2;
334     } else {
335        s = Magic3;
336     }
337  }
338
339  SHA1_Init(&Context);
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);
345
346  memcpy(SessionKey, Digest, SessionKeyLength);
347}
348
349void
350GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
351                 char *InterimKey)
352{
353  SHA_CTX Context;
354  char Digest[SHA_DIGEST_LENGTH];
355
356  SHA1_Init(&Context);
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);
362
363  memcpy(InterimKey, Digest, SessionKeyLength);
364}
365
366#if 0
367static void
368Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
369        int LengthOfDesiredKey)
370{
371  SHA_CTX Context;
372  char Digest[SHA_DIGEST_LENGTH];
373
374  SHA1_Init(&Context);
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);
380
381  memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
382}
383#endif
384
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 */
388void
389mschap_NT(char *passwordHash, char *challenge)
390{
391    u_char response[24];
392
393    ChallengeResponse(challenge, passwordHash, response);
394    memcpy(passwordHash, response, 24);
395    passwordHash[24] = 1;		/* NT-style response */
396}
397
398void
399mschap_LANMan(char *digest, char *challenge, char *secret)
400{
401  static u_char salt[] = "KGS!@#$%";	/* RASAPI32.dll */
402  char SECRET[14], *ptr, *end;
403  u_char hash[16];
404
405  end = SECRET + sizeof SECRET;
406  for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
407    *ptr = toupper(*secret);
408  if (ptr < end)
409    memset(ptr, '\0', end - ptr);
410
411  DesEncrypt(salt, SECRET, hash);
412  DesEncrypt(salt, SECRET + 7, hash + 8);
413
414  ChallengeResponse(challenge, hash, digest);
415}
416