SAMV71 Xplained Ultra Software Package 1.5

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 
00089 /*************************/
00090 /*** LOCAL DEFINITIONS ***/
00091 /*************************/
00092 
00093 
00094 /************************/
00095 /*** LOCAL DATA TYPES ***/
00096 /************************/
00097 typedef struct {
00098     u_char LANManResp[24];
00099     u_char NTResp[24];
00100     u_char UseNT; /* If 1, ignore the LANMan response field */
00101 } MS_ChapResponse;
00102 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
00103    in case this struct gets padded. */
00104 
00105 
00106 
00107 /***********************************/
00108 /*** LOCAL FUNCTION DECLARATIONS ***/
00109 /***********************************/
00110 
00111 /* XXX Don't know what to do with these. */
00112 extern void setkey(const char *);
00113 extern void encrypt(char *, int);
00114 
00115 static void DesEncrypt (u_char *, u_char *, u_char *);
00116 static void MakeKey (u_char *, u_char *);
00117 
00118 #ifdef USE_CRYPT
00119 static void Expand (u_char *, u_char *);
00120 static void Collapse (u_char *, u_char *);
00121 #endif
00122 
00123 static void ChallengeResponse(
00124   u_char *challenge, /* IN   8 octets */
00125   u_char *pwHash,    /* IN  16 octets */
00126   u_char *response   /* OUT 24 octets */
00127 );
00128 static void ChapMS_NT(
00129   char *rchallenge,
00130   int rchallenge_len,
00131   char *secret,
00132   int secret_len,
00133   MS_ChapResponse *response
00134 );
00135 static u_char Get7Bits(
00136   u_char *input,
00137   int startBit
00138 );
00139 
00140 
00141 /***********************************/
00142 /*** PUBLIC FUNCTION DEFINITIONS ***/
00143 /***********************************/
00144 void
00145 ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
00146 {
00147   MS_ChapResponse response;
00148 #ifdef MSLANMAN
00149   extern int ms_lanman;
00150 #endif
00151 
00152 #if 0
00153   CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
00154 #endif
00155   BZERO(&response, sizeof(response));
00156 
00157   /* Calculate both always */
00158   ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
00159 
00160 #ifdef MSLANMAN
00161   ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
00162 
00163   /* prefered method is set by option  */
00164   response.UseNT = !ms_lanman;
00165 #else
00166   response.UseNT = 1;
00167 #endif
00168 
00169   BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
00170   cstate->resp_length = MS_CHAP_RESPONSE_LEN;
00171 }
00172 
00173 
00174 /**********************************/
00175 /*** LOCAL FUNCTION DEFINITIONS ***/
00176 /**********************************/
00177 static void
00178 ChallengeResponse( u_char *challenge, /* IN   8 octets */
00179                    u_char *pwHash,    /* IN  16 octets */
00180                    u_char *response   /* OUT 24 octets */)
00181 {
00182   char    ZPasswordHash[21];
00183 
00184   BZERO(ZPasswordHash, sizeof(ZPasswordHash));
00185   BCOPY(pwHash, ZPasswordHash, 16);
00186 
00187 #if 0
00188   log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
00189 #endif
00190 
00191   DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
00192   DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
00193   DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
00194 
00195 #if 0
00196   log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
00197 #endif
00198 }
00199 
00200 
00201 #ifdef USE_CRYPT
00202 static void
00203 DesEncrypt( u_char *clear, /* IN  8 octets */
00204             u_char *key,   /* IN  7 octets */
00205             u_char *cipher /* OUT 8 octets */)
00206 {
00207   u_char des_key[8];
00208   u_char crypt_key[66];
00209   u_char des_input[66];
00210 
00211   MakeKey(key, des_key);
00212 
00213   Expand(des_key, crypt_key);
00214   setkey(crypt_key);
00215 
00216 #if 0
00217   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
00218              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
00219 #endif
00220 
00221   Expand(clear, des_input);
00222   encrypt(des_input, 0);
00223   Collapse(des_input, cipher);
00224 
00225 #if 0
00226   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00227              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
00228 #endif
00229 }
00230 
00231 #else /* USE_CRYPT */
00232 
00233 static void
00234 DesEncrypt( u_char *clear, /* IN  8 octets */
00235             u_char *key,   /* IN  7 octets */
00236             u_char *cipher /* OUT 8 octets */)
00237 {
00238   des_cblock    des_key;
00239   des_key_schedule  key_schedule;
00240 
00241   MakeKey(key, des_key);
00242 
00243   des_set_key(&des_key, key_schedule);
00244 
00245 #if 0
00246   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
00247              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
00248 #endif
00249 
00250   des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
00251 
00252 #if 0
00253   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00254              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
00255 #endif
00256 }
00257 
00258 #endif /* USE_CRYPT */
00259 
00260 
00261 static u_char
00262 Get7Bits( u_char *input, int startBit)
00263 {
00264   register unsigned int  word;
00265 
00266   word  = (unsigned)input[startBit / 8] << 8;
00267   word |= (unsigned)input[startBit / 8 + 1];
00268 
00269   word >>= 15 - (startBit % 8 + 7);
00270 
00271   return word & 0xFE;
00272 }
00273 
00274 #ifdef USE_CRYPT
00275 
00276 /* in == 8-byte string (expanded version of the 56-bit key)
00277  * out == 64-byte string where each byte is either 1 or 0
00278  * Note that the low-order "bit" is always ignored by by setkey()
00279  */
00280 static void
00281 Expand(u_char *in, u_char *out)
00282 {
00283   int j, c;
00284   int i;
00285 
00286   for(i = 0; i < 64; in++){
00287     c = *in;
00288     for(j = 7; j >= 0; j--) {
00289       *out++ = (c >> j) & 01;
00290     }
00291     i += 8;
00292   }
00293 }
00294 
00295 /* The inverse of Expand
00296  */
00297 static void
00298 Collapse(u_char *in, u_char *out)
00299 {
00300   int j;
00301   int i;
00302   unsigned int c;
00303 
00304   for (i = 0; i < 64; i += 8, out++) {
00305     c = 0;
00306     for (j = 7; j >= 0; j--, in++) {
00307       c |= *in << j;
00308     }
00309     *out = c & 0xff;
00310   }
00311 }
00312 #endif
00313 
00314 static void
00315 MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */
00316          u_char *des_key /* OUT 64 bit DES key with parity bits added */)
00317 {
00318   des_key[0] = Get7Bits(key,  0);
00319   des_key[1] = Get7Bits(key,  7);
00320   des_key[2] = Get7Bits(key, 14);
00321   des_key[3] = Get7Bits(key, 21);
00322   des_key[4] = Get7Bits(key, 28);
00323   des_key[5] = Get7Bits(key, 35);
00324   des_key[6] = Get7Bits(key, 42);
00325   des_key[7] = Get7Bits(key, 49);
00326   
00327 #ifndef USE_CRYPT
00328   des_set_odd_parity((des_cblock *)des_key);
00329 #endif
00330   
00331 #if 0
00332   CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
00333              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
00334   CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
00335              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
00336 #endif
00337 }
00338 
00339 static void
00340 ChapMS_NT( char *rchallenge,
00341            int rchallenge_len,
00342            char *secret,
00343            int secret_len,
00344            MS_ChapResponse *response)
00345 {
00346   int      i;
00347   MDstruct  md4Context;
00348   u_char    unicodePassword[MAX_NT_PASSWORD * 2];
00349   static int  low_byte_first = -1;
00350 
00351   /* Initialize the Unicode version of the secret (== password). */
00352   /* This implicitly supports 8-bit ISO8859/1 characters. */
00353   BZERO(unicodePassword, sizeof(unicodePassword));
00354   for (i = 0; i < secret_len; i++) {
00355     unicodePassword[i * 2] = (u_char)secret[i];
00356   }
00357   MDbegin(&md4Context);
00358   MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */
00359 
00360   if (low_byte_first == -1) {
00361     low_byte_first = (htons((unsigned short int)1) != 1);
00362   }
00363   if (low_byte_first == 0) {
00364     MDreverse((u_long *)&md4Context);  /*  sfb 961105 */
00365   }
00366 
00367   MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */
00368 
00369   ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
00370 }
00371 
00372 #ifdef MSLANMAN
00373 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
00374 
00375 static void
00376 ChapMS_LANMan( char *rchallenge,
00377                int rchallenge_len,
00378                char *secret,
00379                int secret_len,
00380                MS_ChapResponse  *response)
00381 {
00382   int      i;
00383   u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
00384   u_char    PasswordHash[16];
00385   
00386   /* LANMan password is case insensitive */
00387   BZERO(UcasePassword, sizeof(UcasePassword));
00388   for (i = 0; i < secret_len; i++) {
00389     UcasePassword[i] = (u_char)toupper(secret[i]);
00390   }
00391   DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
00392   DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
00393   ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
00394 }
00395 #endif
00396 
00397 #endif /* MSCHAP_SUPPORT */
00398 
00399 #endif /* PPP_SUPPORT */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines