chpms.c
上传用户:yyhongfa
上传日期:2013-01-18
资源大小:267k
文件大小:11k
开发平台:

C/C++

  1. /*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
  2. /*****************************************************************************
  3. * chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
  4. *
  5. * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
  6. * Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
  7. *
  8. * The authors hereby grant permission to use, copy, modify, distribute,
  9. * and license this software and its documentation for any purpose, provided
  10. * that existing copyright notices are retained in all copies and that this
  11. * notice and the following disclaimer are included verbatim in any 
  12. * distributions. No written agreement, license, or royalty fee is required
  13. * for any of the authorized uses.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  18. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. ******************************************************************************
  27. * REVISION HISTORY
  28. *
  29. * 03-01-01 Marc Boucher <marc@mbsi.ca>
  30. *   Ported to lwIP.
  31. * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
  32. * Original based on BSD chap_ms.c.
  33. *****************************************************************************/
  34. /*
  35.  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
  36.  *
  37.  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
  38.  * http://www.strataware.com/
  39.  *
  40.  * All rights reserved.
  41.  *
  42.  * Redistribution and use in source and binary forms are permitted
  43.  * provided that the above copyright notice and this paragraph are
  44.  * duplicated in all such forms and that any documentation,
  45.  * advertising materials, and other materials related to such
  46.  * distribution and use acknowledge that the software was developed
  47.  * by Eric Rosenquist.  The name of the author may not be used to
  48.  * endorse or promote products derived from this software without
  49.  * specific prior written permission.
  50.  *
  51.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  52.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  53.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  54.  */
  55. /*
  56.  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
  57.  *
  58.  *   Implemented LANManager type password response to MS-CHAP challenges.
  59.  *   Now pppd provides both NT style and LANMan style blocks, and the
  60.  *   prefered is set by option "ms-lanman". Default is to use NT.
  61.  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
  62.  *
  63.  *   You should also use DOMAIN\USERNAME as described in README.MSCHAP80
  64.  */
  65. #define USE_CRYPT
  66. #include "ppp.h"
  67. #if MSCHAP_SUPPORT > 0
  68. #include "md4.h"
  69. #ifndef USE_CRYPT
  70. #include "des.h"
  71. #endif
  72. #include "chap.h"
  73. #include "chpms.h"
  74. #include "pppdebug.h"
  75. /*************************/
  76. /*** LOCAL DEFINITIONS ***/
  77. /*************************/
  78. /************************/
  79. /*** LOCAL DATA TYPES ***/
  80. /************************/
  81. typedef struct {
  82.     u_char LANManResp[24];
  83.     u_char NTResp[24];
  84.     u_char UseNT; /* If 1, ignore the LANMan response field */
  85. } MS_ChapResponse;
  86. /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
  87.    in case this struct gets padded. */
  88. /***********************************/
  89. /*** LOCAL FUNCTION DECLARATIONS ***/
  90. /***********************************/
  91. /* XXX Don't know what to do with these. */
  92. extern void setkey(const char *);
  93. extern void encrypt(char *, int);
  94. static void DesEncrypt (u_char *, u_char *, u_char *);
  95. static void MakeKey (u_char *, u_char *);
  96. #ifdef USE_CRYPT
  97. static void Expand (u_char *, u_char *);
  98. static void Collapse (u_char *, u_char *);
  99. #endif
  100. static void ChallengeResponse(
  101. u_char *challenge, /* IN   8 octets */
  102. u_char *pwHash, /* IN  16 octets */
  103. u_char *response /* OUT 24 octets */
  104. );
  105. static void ChapMS_NT(
  106. char *rchallenge,
  107. int rchallenge_len,
  108. char *secret,
  109. int secret_len,
  110. MS_ChapResponse *response
  111. );
  112. static u_char Get7Bits(
  113. u_char *input,
  114. int startBit
  115. );
  116. /***********************************/
  117. /*** PUBLIC FUNCTION DEFINITIONS ***/
  118. /***********************************/
  119. void ChapMS(
  120. chap_state *cstate,
  121. char *rchallenge,
  122. int rchallenge_len,
  123. char *secret,
  124. int secret_len
  125. )
  126. {
  127. MS_ChapResponse response;
  128. #ifdef MSLANMAN
  129. extern int ms_lanman;
  130. #endif
  131. #if 0
  132. CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'n", secret_len, secret));
  133. #endif
  134. BZERO(&response, sizeof(response));
  135. /* Calculate both always */
  136. ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
  137. #ifdef MSLANMAN
  138. ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
  139. /* prefered method is set by option  */
  140. response.UseNT = !ms_lanman;
  141. #else
  142. response.UseNT = 1;
  143. #endif
  144. BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
  145. cstate->resp_length = MS_CHAP_RESPONSE_LEN;
  146. }
  147. /**********************************/
  148. /*** LOCAL FUNCTION DEFINITIONS ***/
  149. /**********************************/
  150. static void ChallengeResponse(
  151. u_char *challenge, /* IN   8 octets */
  152. u_char *pwHash, /* IN  16 octets */
  153. u_char *response /* OUT 24 octets */
  154. )
  155. {
  156. char    ZPasswordHash[21];
  157. BZERO(ZPasswordHash, sizeof(ZPasswordHash));
  158. BCOPY(pwHash, ZPasswordHash, 16);
  159. #if 0
  160. log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
  161. #endif
  162. DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
  163. DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
  164. DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
  165. #if 0
  166. log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
  167. #endif
  168. }
  169. #ifdef USE_CRYPT
  170. static void DesEncrypt(
  171. u_char *clear, /* IN  8 octets */
  172. u_char *key, /* IN  7 octets */
  173. u_char *cipher /* OUT 8 octets */
  174. )
  175. {
  176. u_char des_key[8];
  177. u_char crypt_key[66];
  178. u_char des_input[66];
  179. MakeKey(key, des_key);
  180. Expand(des_key, crypt_key);
  181. setkey(crypt_key);
  182. #if 0
  183. CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02Xn",
  184.        clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
  185. #endif
  186. Expand(clear, des_input);
  187. encrypt(des_input, 0);
  188. Collapse(des_input, cipher);
  189. #if 0
  190. CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02Xn",
  191.        cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
  192. #endif
  193. }
  194. #else /* USE_CRYPT */
  195. static void DesEncrypt(
  196. u_char *clear, /* IN  8 octets */
  197. u_char *key, /* IN  7 octets */
  198. u_char *cipher /* OUT 8 octets */
  199. )
  200. {
  201. des_cblock des_key;
  202. des_key_schedule key_schedule;
  203. MakeKey(key, des_key);
  204. des_set_key(&des_key, key_schedule);
  205. #if 0
  206. CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02Xn",
  207.        clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
  208. #endif
  209. des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
  210. #if 0
  211. CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02Xn",
  212.        cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
  213. #endif
  214. }
  215. #endif /* USE_CRYPT */
  216. static u_char Get7Bits(
  217. u_char *input,
  218. int startBit
  219. )
  220. {
  221. register unsigned int word;
  222. word  = (unsigned)input[startBit / 8] << 8;
  223. word |= (unsigned)input[startBit / 8 + 1];
  224. word >>= 15 - (startBit % 8 + 7);
  225. return word & 0xFE;
  226. }
  227. #ifdef USE_CRYPT
  228. /* in == 8-byte string (expanded version of the 56-bit key)
  229.  * out == 64-byte string where each byte is either 1 or 0
  230.  * Note that the low-order "bit" is always ignored by by setkey()
  231.  */
  232. static void Expand(u_char *in, u_char *out)
  233. {
  234. int j, c;
  235. int i;
  236. for(i = 0; i < 64; in++){
  237. c = *in;
  238. for(j = 7; j >= 0; j--)
  239. *out++ = (c >> j) & 01;
  240. i += 8;
  241. }
  242. }
  243. /* The inverse of Expand
  244.  */
  245. static void Collapse(u_char *in, u_char *out)
  246. {
  247. int j;
  248. int i;
  249. unsigned int c;
  250. for (i = 0; i < 64; i += 8, out++) {
  251. c = 0;
  252. for (j = 7; j >= 0; j--, in++)
  253. c |= *in << j;
  254. *out = c & 0xff;
  255. }
  256. }
  257. #endif
  258. static void MakeKey(
  259. u_char *key, /* IN  56 bit DES key missing parity bits */
  260. u_char *des_key /* OUT 64 bit DES key with parity bits added */
  261. )
  262. {
  263. des_key[0] = Get7Bits(key,  0);
  264. des_key[1] = Get7Bits(key,  7);
  265. des_key[2] = Get7Bits(key, 14);
  266. des_key[3] = Get7Bits(key, 21);
  267. des_key[4] = Get7Bits(key, 28);
  268. des_key[5] = Get7Bits(key, 35);
  269. des_key[6] = Get7Bits(key, 42);
  270. des_key[7] = Get7Bits(key, 49);
  271. #ifndef USE_CRYPT
  272. des_set_odd_parity((des_cblock *)des_key);
  273. #endif
  274. #if 0
  275. CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02Xn",
  276.        key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
  277. CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02Xn",
  278.        des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
  279. #endif
  280. }
  281. static void ChapMS_NT(
  282. char *rchallenge,
  283. int rchallenge_len,
  284. char *secret,
  285. int secret_len,
  286. MS_ChapResponse *response
  287. )
  288. {
  289. int i;
  290. MDstruct md4Context;
  291. u_char unicodePassword[MAX_NT_PASSWORD * 2];
  292. static int low_byte_first = -1;
  293. /* Initialize the Unicode version of the secret (== password). */
  294. /* This implicitly supports 8-bit ISO8859/1 characters. */
  295. BZERO(unicodePassword, sizeof(unicodePassword));
  296. for (i = 0; i < secret_len; i++)
  297. unicodePassword[i * 2] = (u_char)secret[i];
  298. MDbegin(&md4Context);
  299. MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
  300. if (low_byte_first == -1)
  301. low_byte_first = (htons((unsigned short int)1) != 1);
  302. if (low_byte_first == 0)
  303. MDreverse((u_long *)&md4Context);  /*  sfb 961105 */
  304. MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
  305. ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
  306. }
  307. #ifdef MSLANMAN
  308. static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
  309. static ChapMS_LANMan(
  310. char *rchallenge,
  311. int rchallenge_len,
  312. char *secret,
  313. int secret_len,
  314. MS_ChapResponse *response
  315. )
  316. {
  317. int i;
  318. u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
  319. u_char PasswordHash[16];
  320. /* LANMan password is case insensitive */
  321. BZERO(UcasePassword, sizeof(UcasePassword));
  322. for (i = 0; i < secret_len; i++)
  323. UcasePassword[i] = (u_char)toupper(secret[i]);
  324. DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
  325. DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
  326. ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
  327. }
  328. #endif
  329. #endif /* MSCHAP_SUPPORT */