chpms.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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.
  7. *
  8. * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
  9. * Copyright (c) 1997 by Global Election Systems Inc. All rights reserved.
  10. *
  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.
  17. *
  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.
  28. *
  29. ******************************************************************************
  30. * REVISION HISTORY
  31. *
  32. * 03-01-01 Marc Boucher <marc@mbsi.ca>
  33. * Ported to lwIP.
  34. * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
  35. * Original based on BSD chap_ms.c.
  36. *****************************************************************************/
  37. /*
  38. * chap_ms.c - Microsoft MS-CHAP compatible implementation.
  39. *
  40. * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
  41. * http://www.strataware.com/
  42. *
  43. * All rights reserved.
  44. *
  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.
  53. *
  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.
  57. */
  58. /*
  59. * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
  60. *
  61. * Implemented LANManager type password response to MS-CHAP challenges.
  62. * Now pppd provides both NT style and LANMan style blocks, and the
  63. * prefered is set by option "ms-lanman". Default is to use NT.
  64. * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
  65. *
  66. * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
  67. */
  68. #define USE_CRYPT
  69. #include "lwip/opt.h"
  70. #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
  71. #if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
  72. #include "ppp_impl.h"
  73. #include "pppdebug.h"
  74. #include "md4.h"
  75. #ifndef USE_CRYPT
  76. #include "des.h"
  77. #endif
  78. #include "chap.h"
  79. #include "chpms.h"
  80. #include <string.h>
  81. /*************************/
  82. /*** LOCAL DEFINITIONS ***/
  83. /*************************/
  84. /************************/
  85. /*** LOCAL DATA TYPES ***/
  86. /************************/
  87. typedef struct {
  88. u_char LANManResp[24];
  89. u_char NTResp[24];
  90. u_char UseNT; /* If 1, ignore the LANMan response field */
  91. } MS_ChapResponse;
  92. /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
  93. in case this struct gets padded. */
  94. /***********************************/
  95. /*** LOCAL FUNCTION DECLARATIONS ***/
  96. /***********************************/
  97. /* XXX Don't know what to do with these. */
  98. extern void setkey(const char *);
  99. extern void encrypt(char *, int);
  100. static void DesEncrypt (u_char *, u_char *, u_char *);
  101. static void MakeKey (u_char *, u_char *);
  102. #ifdef USE_CRYPT
  103. static void Expand (u_char *, u_char *);
  104. static void Collapse (u_char *, u_char *);
  105. #endif
  106. static void ChallengeResponse(
  107. u_char *challenge, /* IN 8 octets */
  108. u_char *pwHash, /* IN 16 octets */
  109. u_char *response /* OUT 24 octets */
  110. );
  111. static void ChapMS_NT(
  112. char *rchallenge,
  113. int rchallenge_len,
  114. char *secret,
  115. int secret_len,
  116. MS_ChapResponse *response
  117. );
  118. static u_char Get7Bits(
  119. u_char *input,
  120. int startBit
  121. );
  122. static void
  123. ChallengeResponse( u_char *challenge, /* IN 8 octets */
  124. u_char *pwHash, /* IN 16 octets */
  125. u_char *response /* OUT 24 octets */)
  126. {
  127. u_char ZPasswordHash[21];
  128. BZERO(ZPasswordHash, sizeof(ZPasswordHash));
  129. BCOPY(pwHash, ZPasswordHash, 16);
  130. #if 0
  131. log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
  132. #endif
  133. DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
  134. DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
  135. DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
  136. #if 0
  137. log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
  138. #endif
  139. }
  140. #ifdef USE_CRYPT
  141. static void
  142. DesEncrypt( u_char *clear, /* IN 8 octets */
  143. u_char *key, /* IN 7 octets */
  144. u_char *cipher /* OUT 8 octets */)
  145. {
  146. u_char des_key[8];
  147. u_char crypt_key[66];
  148. u_char des_input[66];
  149. MakeKey(key, des_key);
  150. Expand(des_key, crypt_key);
  151. setkey((char*)crypt_key);
  152. #if 0
  153. CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
  154. clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
  155. #endif
  156. Expand(clear, des_input);
  157. encrypt((char*)des_input, 0);
  158. Collapse(des_input, cipher);
  159. #if 0
  160. CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
  161. cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
  162. #endif
  163. }
  164. #else /* USE_CRYPT */
  165. static void
  166. DesEncrypt( u_char *clear, /* IN 8 octets */
  167. u_char *key, /* IN 7 octets */
  168. u_char *cipher /* OUT 8 octets */)
  169. {
  170. des_cblock des_key;
  171. des_key_schedule key_schedule;
  172. MakeKey(key, des_key);
  173. des_set_key(&des_key, key_schedule);
  174. #if 0
  175. CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
  176. clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
  177. #endif
  178. des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
  179. #if 0
  180. CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
  181. cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
  182. #endif
  183. }
  184. #endif /* USE_CRYPT */
  185. static u_char
  186. Get7Bits( u_char *input, int startBit)
  187. {
  188. register unsigned int word;
  189. word = (unsigned)input[startBit / 8] << 8;
  190. word |= (unsigned)input[startBit / 8 + 1];
  191. word >>= 15 - (startBit % 8 + 7);
  192. return word & 0xFE;
  193. }
  194. #ifdef USE_CRYPT
  195. /* in == 8-byte string (expanded version of the 56-bit key)
  196. * out == 64-byte string where each byte is either 1 or 0
  197. * Note that the low-order "bit" is always ignored by by setkey()
  198. */
  199. static void
  200. Expand(u_char *in, u_char *out)
  201. {
  202. int j, c;
  203. int i;
  204. for(i = 0; i < 64; in++){
  205. c = *in;
  206. for(j = 7; j >= 0; j--) {
  207. *out++ = (c >> j) & 01;
  208. }
  209. i += 8;
  210. }
  211. }
  212. /* The inverse of Expand
  213. */
  214. static void
  215. Collapse(u_char *in, u_char *out)
  216. {
  217. int j;
  218. int i;
  219. unsigned int c;
  220. for (i = 0; i < 64; i += 8, out++) {
  221. c = 0;
  222. for (j = 7; j >= 0; j--, in++) {
  223. c |= *in << j;
  224. }
  225. *out = c & 0xff;
  226. }
  227. }
  228. #endif
  229. static void
  230. MakeKey( u_char *key, /* IN 56 bit DES key missing parity bits */
  231. u_char *des_key /* OUT 64 bit DES key with parity bits added */)
  232. {
  233. des_key[0] = Get7Bits(key, 0);
  234. des_key[1] = Get7Bits(key, 7);
  235. des_key[2] = Get7Bits(key, 14);
  236. des_key[3] = Get7Bits(key, 21);
  237. des_key[4] = Get7Bits(key, 28);
  238. des_key[5] = Get7Bits(key, 35);
  239. des_key[6] = Get7Bits(key, 42);
  240. des_key[7] = Get7Bits(key, 49);
  241. #ifndef USE_CRYPT
  242. des_set_odd_parity((des_cblock *)des_key);
  243. #endif
  244. #if 0
  245. CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
  246. key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
  247. CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
  248. des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
  249. #endif
  250. }
  251. static void
  252. ChapMS_NT( char *rchallenge,
  253. int rchallenge_len,
  254. char *secret,
  255. int secret_len,
  256. MS_ChapResponse *response)
  257. {
  258. int i;
  259. MDstruct md4Context;
  260. u_char unicodePassword[MAX_NT_PASSWORD * 2];
  261. static int low_byte_first = -1;
  262. LWIP_UNUSED_ARG(rchallenge_len);
  263. /* Initialize the Unicode version of the secret (== password). */
  264. /* This implicitly supports 8-bit ISO8859/1 characters. */
  265. BZERO(unicodePassword, sizeof(unicodePassword));
  266. for (i = 0; i < secret_len; i++) {
  267. unicodePassword[i * 2] = (u_char)secret[i];
  268. }
  269. MDbegin(&md4Context);
  270. MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
  271. if (low_byte_first == -1) {
  272. low_byte_first = (PP_HTONS((unsigned short int)1) != 1);
  273. }
  274. if (low_byte_first == 0) {
  275. /* @todo: arg type - u_long* or u_int* ? */
  276. MDreverse((unsigned int*)&md4Context); /* sfb 961105 */
  277. }
  278. MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
  279. ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp);
  280. }
  281. #ifdef MSLANMAN
  282. static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
  283. static void
  284. ChapMS_LANMan( char *rchallenge,
  285. int rchallenge_len,
  286. char *secret,
  287. int secret_len,
  288. MS_ChapResponse *response)
  289. {
  290. int i;
  291. u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
  292. u_char PasswordHash[16];
  293. /* LANMan password is case insensitive */
  294. BZERO(UcasePassword, sizeof(UcasePassword));
  295. for (i = 0; i < secret_len; i++) {
  296. UcasePassword[i] = (u_char)toupper(secret[i]);
  297. }
  298. DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
  299. DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
  300. ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
  301. }
  302. #endif
  303. void
  304. ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
  305. {
  306. MS_ChapResponse response;
  307. #ifdef MSLANMAN
  308. extern int ms_lanman;
  309. #endif
  310. #if 0
  311. CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret));
  312. #endif
  313. BZERO(&response, sizeof(response));
  314. /* Calculate both always */
  315. ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
  316. #ifdef MSLANMAN
  317. ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
  318. /* prefered method is set by option */
  319. response.UseNT = !ms_lanman;
  320. #else
  321. response.UseNT = 1;
  322. #endif
  323. BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
  324. cstate->resp_length = MS_CHAP_RESPONSE_LEN;
  325. }
  326. #endif /* MSCHAP_SUPPORT */
  327. #endif /* PPP_SUPPORT */