NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chpms.c Source File

chpms.c

00001 /*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
00002 /*** The original PPPD code is written in a way to require either the UNIX DES
00003      encryption functions encrypt(3) and setkey(3) or the DES library libdes.
00004      Since both is not included in lwIP, MSCHAP currently does not work! */
00005 /*****************************************************************************
00006 * chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
00007 *
00008 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00009 * Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
00010 *
00011 * The authors hereby grant permission to use, copy, modify, distribute,
00012 * and license this software and its documentation for any purpose, provided
00013 * that existing copyright notices are retained in all copies and that this
00014 * notice and the following disclaimer are included verbatim in any 
00015 * distributions. No written agreement, license, or royalty fee is required
00016 * for any of the authorized uses.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00019 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00021 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 *
00029 ******************************************************************************
00030 * REVISION HISTORY
00031 *
00032 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00033 *   Ported to lwIP.
00034 * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00035 *   Original based on BSD chap_ms.c.
00036 *****************************************************************************/
00037 /*
00038  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
00039  *
00040  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
00041  * http://www.strataware.com/
00042  *
00043  * All rights reserved.
00044  *
00045  * Redistribution and use in source and binary forms are permitted
00046  * provided that the above copyright notice and this paragraph are
00047  * duplicated in all such forms and that any documentation,
00048  * advertising materials, and other materials related to such
00049  * distribution and use acknowledge that the software was developed
00050  * by Eric Rosenquist.  The name of the author may not be used to
00051  * endorse or promote products derived from this software without
00052  * specific prior written permission.
00053  *
00054  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00055  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00056  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00057  */
00058 
00059 /*
00060  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
00061  *
00062  *   Implemented LANManager type password response to MS-CHAP challenges.
00063  *   Now pppd provides both NT style and LANMan style blocks, and the
00064  *   prefered is set by option "ms-lanman". Default is to use NT.
00065  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
00066  *
00067  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
00068  */
00069 
00070 #define USE_CRYPT
00071 
00072 #include "lwip/opt.h"
00073 
00074 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00075 
00076 #if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00077 
00078 #include "ppp.h"
00079 #include "pppdebug.h"
00080 
00081 #include "md4.h"
00082 #ifndef USE_CRYPT
00083 #include "des.h"
00084 #endif
00085 #include "chap.h"
00086 #include "chpms.h"
00087 
00088 #include <string.h>
00089 
00090 
00091 /*************************/
00092 /*** LOCAL DEFINITIONS ***/
00093 /*************************/
00094 
00095 
00096 /************************/
00097 /*** LOCAL DATA TYPES ***/
00098 /************************/
00099 typedef struct {
00100     u_char LANManResp[24];
00101     u_char NTResp[24];
00102     u_char UseNT; /* If 1, ignore the LANMan response field */
00103 } MS_ChapResponse;
00104 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
00105    in case this struct gets padded. */
00106 
00107 
00108 
00109 /***********************************/
00110 /*** LOCAL FUNCTION DECLARATIONS ***/
00111 /***********************************/
00112 
00113 /* XXX Don't know what to do with these. */
00114 extern void setkey(const char *);
00115 extern void encrypt(char *, int);
00116 
00117 static void DesEncrypt (u_char *, u_char *, u_char *);
00118 static void MakeKey (u_char *, u_char *);
00119 
00120 #ifdef USE_CRYPT
00121 static void Expand (u_char *, u_char *);
00122 static void Collapse (u_char *, u_char *);
00123 #endif
00124 
00125 static void ChallengeResponse(
00126   u_char *challenge, /* IN   8 octets */
00127   u_char *pwHash,    /* IN  16 octets */
00128   u_char *response   /* OUT 24 octets */
00129 );
00130 static void ChapMS_NT(
00131   char *rchallenge,
00132   int rchallenge_len,
00133   char *secret,
00134   int secret_len,
00135   MS_ChapResponse *response
00136 );
00137 static u_char Get7Bits(
00138   u_char *input,
00139   int startBit
00140 );
00141 
00142 static void
00143 ChallengeResponse( u_char *challenge, /* IN   8 octets */
00144                    u_char *pwHash,    /* IN  16 octets */
00145                    u_char *response   /* OUT 24 octets */)
00146 {
00147   u_char    ZPasswordHash[21];
00148 
00149   BZERO(ZPasswordHash, sizeof(ZPasswordHash));
00150   BCOPY(pwHash, ZPasswordHash, 16);
00151 
00152 #if 0
00153   log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
00154 #endif
00155 
00156   DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
00157   DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
00158   DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
00159 
00160 #if 0
00161   log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
00162 #endif
00163 }
00164 
00165 
00166 #ifdef USE_CRYPT
00167 static void
00168 DesEncrypt( u_char *clear, /* IN  8 octets */
00169             u_char *key,   /* IN  7 octets */
00170             u_char *cipher /* OUT 8 octets */)
00171 {
00172   u_char des_key[8];
00173   u_char crypt_key[66];
00174   u_char des_input[66];
00175 
00176   MakeKey(key, des_key);
00177 
00178   Expand(des_key, crypt_key);
00179   setkey((char*)crypt_key);
00180 
00181 #if 0
00182   CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
00183              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
00184 #endif
00185 
00186   Expand(clear, des_input);
00187   encrypt((char*)des_input, 0);
00188   Collapse(des_input, cipher);
00189 
00190 #if 0
00191   CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00192              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
00193 #endif
00194 }
00195 
00196 #else /* USE_CRYPT */
00197 
00198 static void
00199 DesEncrypt( u_char *clear, /* IN  8 octets */
00200             u_char *key,   /* IN  7 octets */
00201             u_char *cipher /* OUT 8 octets */)
00202 {
00203   des_cblock    des_key;
00204   des_key_schedule  key_schedule;
00205 
00206   MakeKey(key, des_key);
00207 
00208   des_set_key(&des_key, key_schedule);
00209 
00210 #if 0
00211   CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
00212              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
00213 #endif
00214 
00215   des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
00216 
00217 #if 0
00218   CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00219              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
00220 #endif
00221 }
00222 
00223 #endif /* USE_CRYPT */
00224 
00225 
00226 static u_char
00227 Get7Bits( u_char *input, int startBit)
00228 {
00229   register unsigned int  word;
00230 
00231   word  = (unsigned)input[startBit / 8] << 8;
00232   word |= (unsigned)input[startBit / 8 + 1];
00233 
00234   word >>= 15 - (startBit % 8 + 7);
00235 
00236   return word & 0xFE;
00237 }
00238 
00239 #ifdef USE_CRYPT
00240 
00241 /* in == 8-byte string (expanded version of the 56-bit key)
00242  * out == 64-byte string where each byte is either 1 or 0
00243  * Note that the low-order "bit" is always ignored by by setkey()
00244  */
00245 static void
00246 Expand(u_char *in, u_char *out)
00247 {
00248   int j, c;
00249   int i;
00250 
00251   for(i = 0; i < 64; in++){
00252     c = *in;
00253     for(j = 7; j >= 0; j--) {
00254       *out++ = (c >> j) & 01;
00255     }
00256     i += 8;
00257   }
00258 }
00259 
00260 /* The inverse of Expand
00261  */
00262 static void
00263 Collapse(u_char *in, u_char *out)
00264 {
00265   int j;
00266   int i;
00267   unsigned int c;
00268 
00269   for (i = 0; i < 64; i += 8, out++) {
00270     c = 0;
00271     for (j = 7; j >= 0; j--, in++) {
00272       c |= *in << j;
00273     }
00274     *out = c & 0xff;
00275   }
00276 }
00277 #endif
00278 
00279 static void
00280 MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */
00281          u_char *des_key /* OUT 64 bit DES key with parity bits added */)
00282 {
00283   des_key[0] = Get7Bits(key,  0);
00284   des_key[1] = Get7Bits(key,  7);
00285   des_key[2] = Get7Bits(key, 14);
00286   des_key[3] = Get7Bits(key, 21);
00287   des_key[4] = Get7Bits(key, 28);
00288   des_key[5] = Get7Bits(key, 35);
00289   des_key[6] = Get7Bits(key, 42);
00290   des_key[7] = Get7Bits(key, 49);
00291   
00292 #ifndef USE_CRYPT
00293   des_set_odd_parity((des_cblock *)des_key);
00294 #endif
00295   
00296 #if 0
00297   CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
00298              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
00299   CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00300              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
00301 #endif
00302 }
00303 
00304 static void
00305 ChapMS_NT( char *rchallenge,
00306            int rchallenge_len,
00307            char *secret,
00308            int secret_len,
00309            MS_ChapResponse *response)
00310 {
00311   int      i;
00312   MDstruct  md4Context;
00313   u_char    unicodePassword[MAX_NT_PASSWORD * 2];
00314   static int  low_byte_first = -1;
00315 
00316   LWIP_UNUSED_ARG(rchallenge_len);
00317 
00318   /* Initialize the Unicode version of the secret (== password). */
00319   /* This implicitly supports 8-bit ISO8859/1 characters. */
00320   BZERO(unicodePassword, sizeof(unicodePassword));
00321   for (i = 0; i < secret_len; i++) {
00322     unicodePassword[i * 2] = (u_char)secret[i];
00323   }
00324   MDbegin(&md4Context);
00325   MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */
00326 
00327   if (low_byte_first == -1) {
00328     low_byte_first = (PP_HTONS((unsigned short int)1) != 1);
00329   }
00330   if (low_byte_first == 0) {
00331     /* @todo: arg type - u_long* or u_int* ? */
00332     MDreverse((unsigned int*)&md4Context);  /*  sfb 961105 */
00333   }
00334 
00335   MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */
00336 
00337   ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp);
00338 }
00339 
00340 #ifdef MSLANMAN
00341 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
00342 
00343 static void
00344 ChapMS_LANMan( char *rchallenge,
00345                int rchallenge_len,
00346                char *secret,
00347                int secret_len,
00348                MS_ChapResponse  *response)
00349 {
00350   int      i;
00351   u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
00352   u_char    PasswordHash[16];
00353   
00354   /* LANMan password is case insensitive */
00355   BZERO(UcasePassword, sizeof(UcasePassword));
00356   for (i = 0; i < secret_len; i++) {
00357     UcasePassword[i] = (u_char)toupper(secret[i]);
00358   }
00359   DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
00360   DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
00361   ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
00362 }
00363 #endif
00364 
00365 void
00366 ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
00367 {
00368   MS_ChapResponse response;
00369 #ifdef MSLANMAN
00370   extern int ms_lanman;
00371 #endif
00372 
00373 #if 0
00374   CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret));
00375 #endif
00376   BZERO(&response, sizeof(response));
00377 
00378   /* Calculate both always */
00379   ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
00380 
00381 #ifdef MSLANMAN
00382   ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
00383 
00384   /* prefered method is set by option  */
00385   response.UseNT = !ms_lanman;
00386 #else
00387   response.UseNT = 1;
00388 #endif
00389 
00390   BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
00391   cstate->resp_length = MS_CHAP_RESPONSE_LEN;
00392 }
00393 
00394 #endif /* MSCHAP_SUPPORT */
00395 
00396 #endif /* PPP_SUPPORT */