1 /*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
2 /*** The original PPPD code is written in a way to require either the UNIX DES
3 encryption functions encrypt(3) and setkey(3) or the DES library libdes.
4 Since both is not included in lwIP, MSCHAP currently does not work! */
5 /*****************************************************************************
6 * chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
8 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
9 * Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
11 * The authors hereby grant permission to use, copy, modify, distribute,
12 * and license this software and its documentation for any purpose, provided
13 * that existing copyright notices are retained in all copies and that this
14 * notice and the following disclaimer are included verbatim in any
15 * distributions. No written agreement, license, or royalty fee is required
16 * for any of the authorized uses.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 ******************************************************************************
32 * 03-01-01 Marc Boucher <marc@mbsi.ca>
34 * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
35 * Original based on BSD chap_ms.c.
36 *****************************************************************************/
38 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
40 * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
41 * http://www.strataware.com/
43 * All rights reserved.
45 * Redistribution and use in source and binary forms are permitted
46 * provided that the above copyright notice and this paragraph are
47 * duplicated in all such forms and that any documentation,
48 * advertising materials, and other materials related to such
49 * distribution and use acknowledge that the software was developed
50 * by Eric Rosenquist. The name of the author may not be used to
51 * endorse or promote products derived from this software without
52 * specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
55 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
62 * Implemented LANManager type password response to MS-CHAP challenges.
63 * Now pppd provides both NT style and LANMan style blocks, and the
64 * prefered is set by option "ms-lanman". Default is to use NT.
65 * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
67 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
74 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
76 #if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
91 /*************************/
92 /*** LOCAL DEFINITIONS ***/
93 /*************************/
96 /************************/
97 /*** LOCAL DATA TYPES ***/
98 /************************/
100 u_char LANManResp
[24];
102 u_char UseNT
; /* If 1, ignore the LANMan response field */
104 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
105 in case this struct gets padded. */
109 /***********************************/
110 /*** LOCAL FUNCTION DECLARATIONS ***/
111 /***********************************/
113 /* XXX Don't know what to do with these. */
114 extern void setkey(const char *);
115 extern void encrypt(char *, int);
117 static void DesEncrypt (u_char
*, u_char
*, u_char
*);
118 static void MakeKey (u_char
*, u_char
*);
121 static void Expand (u_char
*, u_char
*);
122 static void Collapse (u_char
*, u_char
*);
125 static void ChallengeResponse(
126 u_char
*challenge
, /* IN 8 octets */
127 u_char
*pwHash
, /* IN 16 octets */
128 u_char
*response
/* OUT 24 octets */
130 static void ChapMS_NT(
135 MS_ChapResponse
*response
137 static u_char
Get7Bits(
143 ChallengeResponse( u_char
*challenge
, /* IN 8 octets */
144 u_char
*pwHash
, /* IN 16 octets */
145 u_char
*response
/* OUT 24 octets */)
147 u_char ZPasswordHash
[21];
149 BZERO(ZPasswordHash
, sizeof(ZPasswordHash
));
150 BCOPY(pwHash
, ZPasswordHash
, 16);
153 log_packet(ZPasswordHash
, sizeof(ZPasswordHash
), "ChallengeResponse - ZPasswordHash", LOG_DEBUG
);
156 DesEncrypt(challenge
, ZPasswordHash
+ 0, response
+ 0);
157 DesEncrypt(challenge
, ZPasswordHash
+ 7, response
+ 8);
158 DesEncrypt(challenge
, ZPasswordHash
+ 14, response
+ 16);
161 log_packet(response
, 24, "ChallengeResponse - response", LOG_DEBUG
);
168 DesEncrypt( u_char
*clear
, /* IN 8 octets */
169 u_char
*key
, /* IN 7 octets */
170 u_char
*cipher
/* OUT 8 octets */)
173 u_char crypt_key
[66];
174 u_char des_input
[66];
176 MakeKey(key
, des_key
);
178 Expand(des_key
, crypt_key
);
179 setkey((char*)crypt_key
);
182 CHAPDEBUG(LOG_INFO
, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
183 clear
[0], clear
[1], clear
[2], clear
[3], clear
[4], clear
[5], clear
[6], clear
[7]));
186 Expand(clear
, des_input
);
187 encrypt((char*)des_input
, 0);
188 Collapse(des_input
, cipher
);
191 CHAPDEBUG(LOG_INFO
, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
192 cipher
[0], cipher
[1], cipher
[2], cipher
[3], cipher
[4], cipher
[5], cipher
[6], cipher
[7]));
196 #else /* USE_CRYPT */
199 DesEncrypt( u_char
*clear
, /* IN 8 octets */
200 u_char
*key
, /* IN 7 octets */
201 u_char
*cipher
/* OUT 8 octets */)
204 des_key_schedule key_schedule
;
206 MakeKey(key
, des_key
);
208 des_set_key(&des_key
, key_schedule
);
211 CHAPDEBUG(LOG_INFO
, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
212 clear
[0], clear
[1], clear
[2], clear
[3], clear
[4], clear
[5], clear
[6], clear
[7]));
215 des_ecb_encrypt((des_cblock
*)clear
, (des_cblock
*)cipher
, key_schedule
, 1);
218 CHAPDEBUG(LOG_INFO
, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
219 cipher
[0], cipher
[1], cipher
[2], cipher
[3], cipher
[4], cipher
[5], cipher
[6], cipher
[7]));
223 #endif /* USE_CRYPT */
227 Get7Bits( u_char
*input
, int startBit
)
229 register unsigned int word
;
231 word
= (unsigned)input
[startBit
/ 8] << 8;
232 word
|= (unsigned)input
[startBit
/ 8 + 1];
234 word
>>= 15 - (startBit
% 8 + 7);
241 /* in == 8-byte string (expanded version of the 56-bit key)
242 * out == 64-byte string where each byte is either 1 or 0
243 * Note that the low-order "bit" is always ignored by by setkey()
246 Expand(u_char
*in
, u_char
*out
)
251 for(i
= 0; i
< 64; in
++){
253 for(j
= 7; j
>= 0; j
--) {
254 *out
++ = (c
>> j
) & 01;
260 /* The inverse of Expand
263 Collapse(u_char
*in
, u_char
*out
)
269 for (i
= 0; i
< 64; i
+= 8, out
++) {
271 for (j
= 7; j
>= 0; j
--, in
++) {
280 MakeKey( u_char
*key
, /* IN 56 bit DES key missing parity bits */
281 u_char
*des_key
/* OUT 64 bit DES key with parity bits added */)
283 des_key
[0] = Get7Bits(key
, 0);
284 des_key
[1] = Get7Bits(key
, 7);
285 des_key
[2] = Get7Bits(key
, 14);
286 des_key
[3] = Get7Bits(key
, 21);
287 des_key
[4] = Get7Bits(key
, 28);
288 des_key
[5] = Get7Bits(key
, 35);
289 des_key
[6] = Get7Bits(key
, 42);
290 des_key
[7] = Get7Bits(key
, 49);
293 des_set_odd_parity((des_cblock
*)des_key
);
297 CHAPDEBUG(LOG_INFO
, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
298 key
[0], key
[1], key
[2], key
[3], key
[4], key
[5], key
[6]));
299 CHAPDEBUG(LOG_INFO
, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
300 des_key
[0], des_key
[1], des_key
[2], des_key
[3], des_key
[4], des_key
[5], des_key
[6], des_key
[7]));
305 ChapMS_NT( char *rchallenge
,
309 MS_ChapResponse
*response
)
313 u_char unicodePassword
[MAX_NT_PASSWORD
* 2];
314 static int low_byte_first
= -1;
316 LWIP_UNUSED_ARG(rchallenge_len
);
318 /* Initialize the Unicode version of the secret (== password). */
319 /* This implicitly supports 8-bit ISO8859/1 characters. */
320 BZERO(unicodePassword
, sizeof(unicodePassword
));
321 for (i
= 0; i
< secret_len
; i
++) {
322 unicodePassword
[i
* 2] = (u_char
)secret
[i
];
324 MDbegin(&md4Context
);
325 MDupdate(&md4Context
, unicodePassword
, secret_len
* 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
327 if (low_byte_first
== -1) {
328 low_byte_first
= (PP_HTONS((unsigned short int)1) != 1);
330 if (low_byte_first
== 0) {
331 /* @todo: arg type - u_long* or u_int* ? */
332 MDreverse((unsigned int*)&md4Context
); /* sfb 961105 */
335 MDupdate(&md4Context
, NULL
, 0); /* Tell MD4 we're done */
337 ChallengeResponse((u_char
*)rchallenge
, (u_char
*)md4Context
.buffer
, response
->NTResp
);
341 static u_char
*StdText
= (u_char
*)"KGS!@#$%"; /* key from rasapi32.dll */
344 ChapMS_LANMan( char *rchallenge
,
348 MS_ChapResponse
*response
)
351 u_char UcasePassword
[MAX_NT_PASSWORD
]; /* max is actually 14 */
352 u_char PasswordHash
[16];
354 /* LANMan password is case insensitive */
355 BZERO(UcasePassword
, sizeof(UcasePassword
));
356 for (i
= 0; i
< secret_len
; i
++) {
357 UcasePassword
[i
] = (u_char
)toupper(secret
[i
]);
359 DesEncrypt( StdText
, UcasePassword
+ 0, PasswordHash
+ 0 );
360 DesEncrypt( StdText
, UcasePassword
+ 7, PasswordHash
+ 8 );
361 ChallengeResponse(rchallenge
, PasswordHash
, response
->LANManResp
);
366 ChapMS( chap_state
*cstate
, char *rchallenge
, int rchallenge_len
, char *secret
, int secret_len
)
368 MS_ChapResponse response
;
370 extern int ms_lanman
;
374 CHAPDEBUG(LOG_INFO
, ("ChapMS: secret is '%.*s'\n", secret_len
, secret
));
376 BZERO(&response
, sizeof(response
));
378 /* Calculate both always */
379 ChapMS_NT(rchallenge
, rchallenge_len
, secret
, secret_len
, &response
);
382 ChapMS_LANMan(rchallenge
, rchallenge_len
, secret
, secret_len
, &response
);
384 /* prefered method is set by option */
385 response
.UseNT
= !ms_lanman
;
390 BCOPY(&response
, cstate
->response
, MS_CHAP_RESPONSE_LEN
);
391 cstate
->resp_length
= MS_CHAP_RESPONSE_LEN
;
394 #endif /* MSCHAP_SUPPORT */
396 #endif /* PPP_SUPPORT */