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
61static 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
67static 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 */
75struct 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
81static u_char
82Get7Bits(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 */
96static void
97MakeKey(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
111static void /* IN 8 octets IN 7 octest OUT 8 octets */
112DesEncrypt(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
122static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
123ChallengeResponse(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
135void
136NtPasswordHash(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
145void
146HashNtPasswordHash(char *hash, char *hashhash)
147{
148  MD4_CTX MD4context;
149
150  MD4Init(&MD4context);
151  MD4Update(&MD4context, hash, 16);
152  MD4Final(hashhash, &MD4context);
153}
154
155static void
156ChallengeHash(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
179void
180GenerateNTResponse(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
194static char *
195SHA1_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
215void
216GenerateAuthenticatorResponse(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
279void
280GetMasterKey(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
297void
298GetAsymetricStartKey(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
351void
352GetNewKeyFromSHA(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
369static void
370Get_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 */
390void
391mschap_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
400void
401mschap_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