Deleted Added
full compact
chap_ms.c (96387) chap_ms.c (98243)
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 *
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: head/usr.sbin/ppp/chap_ms.c 96387 2002-05-11 03:47:15Z brian $
29 * $FreeBSD: head/usr.sbin/ppp/chap_ms.c 98243 2002-06-15 08:03:30Z 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)
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{
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)
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{
145{
146 MD4_CTX MD4context;
147
148 MD4Init(&MD4context);
149 MD4Update(&MD4context, hash, 16);
150 MD4Final(hashhash, &MD4context);
151}
152
153void
154ChallengeHash(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, '\\');
146 MD4_CTX MD4context;
147
148 MD4Init(&MD4context);
149 MD4Update(&MD4context, hash, 16);
150 MD4Final(hashhash, &MD4context);
151}
152
153void
154ChallengeHash(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)
162 if(NULL == Name)
163 Name = UserName;
164 else
165 Name++;
166
167 SHA1_Init(&Context);
168
163 Name = UserName;
164 else
165 Name++;
166
167 SHA1_Init(&Context);
168
169 SHA1_Update(&Context, PeerChallenge, 16);
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, 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
193static char *
194SHA1_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
214void
215GenerateAuthenticatorResponse(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);
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, 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
193static char *
194SHA1_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
214void
215GenerateAuthenticatorResponse(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,
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}
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
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}
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}