Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1997        Gabor Kincses <gabor (at) acm.org>
      3  *               1997 - 2001 Brian Somers <brian (at) Awfulhak.org>
      4  *          based on work by Eric Rosenquist
      5  *                           Strata Software Limited.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  *
     29  * $FreeBSD: src/usr.sbin/ppp/chap_ms.c,v 1.20.26.1 2010/12/21 17:10:29 kensmith Exp $
     30  */
     31 
     32 #include <ctype.h>
     33 #ifdef __FreeBSD__
     34 #include <openssl/des.h>
     35 #include <sha.h>
     36 #else
     37 #include <sys/types.h>
     38 #include <stdlib.h>
     39 #ifdef __NetBSD__
     40 #include <openssl/des.h>
     41 #else
     42 #include <des.h>
     43 #endif
     44 #include <openssl/sha.h>
     45 #endif
     46 #include <md4.h>
     47 #include <string.h>
     48 
     49 #include "chap_ms.h"
     50 
     51 /*
     52  * Documentation & specifications:
     53  *
     54  * MS-CHAP (CHAP80)	rfc2433
     55  * MS-CHAP-V2 (CHAP81)	rfc2759
     56  * MPPE key management	draft-ietf-pppext-mppe-keys-02.txt
     57  */
     58 
     59 static char SHA1_Pad1[40] =
     60   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     61    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     62    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     63    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     64 
     65 static char SHA1_Pad2[40] =
     66   {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
     67    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
     68    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
     69    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
     70 
     71 /* unused, for documentation only */
     72 /* only NTResp is filled in for FreeBSD */
     73 struct MS_ChapResponse {
     74     u_char LANManResp[24];
     75     u_char NTResp[24];
     76     u_char UseNT;	/* If 1, ignore the LANMan response field */
     77 };
     78 
     79 static u_char
     80 Get7Bits(u_char *input, int startBit)
     81 {
     82     register unsigned int	word;
     83 
     84     word  = (unsigned)input[startBit / 8] << 8;
     85     word |= (unsigned)input[startBit / 8 + 1];
     86 
     87     word >>= 15 - (startBit % 8 + 7);
     88 
     89     return word & 0xFE;
     90 }
     91 
     92 /* IN  56 bit DES key missing parity bits
     93    OUT 64 bit DES key with parity bits added */
     94 static void
     95 MakeKey(u_char *key, u_char *des_key)
     96 {
     97     des_key[0] = Get7Bits(key,  0);
     98     des_key[1] = Get7Bits(key,  7);
     99     des_key[2] = Get7Bits(key, 14);
    100     des_key[3] = Get7Bits(key, 21);
    101     des_key[4] = Get7Bits(key, 28);
    102     des_key[5] = Get7Bits(key, 35);
    103     des_key[6] = Get7Bits(key, 42);
    104     des_key[7] = Get7Bits(key, 49);
    105 
    106     des_set_odd_parity((des_cblock *)des_key);
    107 }
    108 
    109 static void /* IN 8 octets IN 7 octest OUT 8 octets */
    110 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
    111 {
    112     des_cblock		des_key;
    113     des_key_schedule	key_schedule;
    114 
    115     MakeKey(key, des_key);
    116     des_set_key(&des_key, key_schedule);
    117     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
    118 }
    119 
    120 static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
    121 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
    122 {
    123     char    ZPasswordHash[21];
    124 
    125     memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
    126     memcpy(ZPasswordHash, pwHash, 16);
    127 
    128     DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
    129     DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
    130     DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
    131 }
    132 
    133 void
    134 NtPasswordHash(char *key, int keylen, char *hash)
    135 {
    136   MD4_CTX MD4context;
    137 
    138   MD4Init(&MD4context);
    139   MD4Update(&MD4context, key, keylen);
    140   MD4Final(hash, &MD4context);
    141 }
    142 
    143 void
    144 HashNtPasswordHash(char *hash, char *hashhash)
    145 {
    146   MD4_CTX MD4context;
    147 
    148   MD4Init(&MD4context);
    149   MD4Update(&MD4context, hash, 16);
    150   MD4Final(hashhash, &MD4context);
    151 }
    152 
    153 static void
    154 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
    155               char *UserName, char *Challenge)
    156 {
    157   SHA_CTX Context;
    158   char Digest[SHA_DIGEST_LENGTH];
    159   char *Name;
    160 
    161   Name = strrchr(UserName, '\\');
    162   if(NULL == Name)
    163     Name = UserName;
    164   else
    165     Name++;
    166 
    167   SHA1_Init(&Context);
    168 
    169   SHA1_Update(&Context, PeerChallenge, 16);
    170   SHA1_Update(&Context, AuthenticatorChallenge, 16);
    171   SHA1_Update(&Context, Name, strlen(Name));
    172 
    173   SHA1_Final(Digest, &Context);
    174   memcpy(Challenge, Digest, 8);
    175 }
    176 
    177 void
    178 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
    179                    char *UserName, char *Password,
    180                    int PasswordLen, char *Response)
    181 {
    182   char Challenge[8];
    183   char PasswordHash[16];
    184 
    185   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
    186   NtPasswordHash(Password, PasswordLen, PasswordHash);
    187   ChallengeResponse(Challenge, PasswordHash, Response);
    188 }
    189 
    190 #ifndef __FreeBSD__
    191 #define LENGTH 20
    192 static char *
    193 SHA1_End(SHA_CTX *ctx, char *buf)
    194 {
    195     int i;
    196     unsigned char digest[LENGTH];
    197     static const char hex[]="0123456789abcdef";
    198 
    199     if (!buf)
    200         buf = malloc(2*LENGTH + 1);
    201     if (!buf)
    202         return 0;
    203     SHA1_Final(digest, ctx);
    204     for (i = 0; i < LENGTH; i++) {
    205         buf[i+i] = hex[digest[i] >> 4];
    206         buf[i+i+1] = hex[digest[i] & 0x0f];
    207     }
    208     buf[i+i] = '\0';
    209     return buf;
    210 }
    211 #endif
    212 
    213 void
    214 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
    215                               char *NTResponse, char *PeerChallenge,
    216                               char *AuthenticatorChallenge, char *UserName,
    217                               char *AuthenticatorResponse)
    218 {
    219   SHA_CTX Context;
    220   char PasswordHash[16];
    221   char PasswordHashHash[16];
    222   char Challenge[8];
    223   u_char Digest[SHA_DIGEST_LENGTH];
    224   int i;
    225 
    226       /*
    227        * "Magic" constants used in response generation
    228        */
    229   char Magic1[39] =
    230          {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
    231           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
    232           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
    233           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
    234 
    235 
    236   char Magic2[41] =
    237          {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
    238           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
    239           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
    240           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
    241           0x6E};
    242       /*
    243        * Hash the password with MD4
    244        */
    245   NtPasswordHash(Password, PasswordLen, PasswordHash);
    246       /*
    247        * Now hash the hash
    248        */
    249   HashNtPasswordHash(PasswordHash, PasswordHashHash);
    250 
    251   SHA1_Init(&Context);
    252   SHA1_Update(&Context, PasswordHashHash, 16);
    253   SHA1_Update(&Context, NTResponse, 24);
    254   SHA1_Update(&Context, Magic1, 39);
    255   SHA1_Final(Digest, &Context);
    256   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge);
    257   SHA1_Init(&Context);
    258   SHA1_Update(&Context, Digest, 20);
    259   SHA1_Update(&Context, Challenge, 8);
    260   SHA1_Update(&Context, Magic2, 41);
    261 
    262       /*
    263        * Encode the value of 'Digest' as "S=" followed by
    264        * 40 ASCII hexadecimal digits and return it in
    265        * AuthenticatorResponse.
    266        * For example,
    267        *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
    268        */
    269   AuthenticatorResponse[0] = 'S';
    270   AuthenticatorResponse[1] = '=';
    271   SHA1_End(&Context, AuthenticatorResponse + 2);
    272   for (i=2; i<42; i++)
    273     AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
    274 
    275 }
    276 
    277 void
    278 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
    279 {
    280   char Digest[SHA_DIGEST_LENGTH];
    281   SHA_CTX Context;
    282   static char Magic1[27] =
    283       {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
    284        0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
    285        0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
    286 
    287   SHA1_Init(&Context);
    288   SHA1_Update(&Context, PasswordHashHash, 16);
    289   SHA1_Update(&Context, NTResponse, 24);
    290   SHA1_Update(&Context, Magic1, 27);
    291   SHA1_Final(Digest, &Context);
    292   memcpy(MasterKey, Digest, 16);
    293 }
    294 
    295 void
    296 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
    297                      int IsSend, int IsServer)
    298 {
    299   char Digest[SHA_DIGEST_LENGTH];
    300   SHA_CTX Context;
    301   char *s;
    302 
    303   static char Magic2[84] =
    304       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
    305        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
    306        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    307        0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
    308        0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
    309        0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
    310        0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    311        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
    312        0x6b, 0x65, 0x79, 0x2e};
    313 
    314   static char Magic3[84] =
    315       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
    316        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
    317        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
    318        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
    319        0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
    320        0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
    321        0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
    322        0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
    323        0x6b, 0x65, 0x79, 0x2e};
    324 
    325   if (IsSend) {
    326      if (IsServer) {
    327         s = Magic3;
    328      } else {
    329         s = Magic2;
    330      }
    331   } else {
    332      if (IsServer) {
    333         s = Magic2;
    334      } else {
    335         s = Magic3;
    336      }
    337   }
    338 
    339   SHA1_Init(&Context);
    340   SHA1_Update(&Context, MasterKey, 16);
    341   SHA1_Update(&Context, SHA1_Pad1, 40);
    342   SHA1_Update(&Context, s, 84);
    343   SHA1_Update(&Context, SHA1_Pad2, 40);
    344   SHA1_Final(Digest, &Context);
    345 
    346   memcpy(SessionKey, Digest, SessionKeyLength);
    347 }
    348 
    349 void
    350 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
    351                  char *InterimKey)
    352 {
    353   SHA_CTX Context;
    354   char Digest[SHA_DIGEST_LENGTH];
    355 
    356   SHA1_Init(&Context);
    357   SHA1_Update(&Context, StartKey, SessionKeyLength);
    358   SHA1_Update(&Context, SHA1_Pad1, 40);
    359   SHA1_Update(&Context, SessionKey, SessionKeyLength);
    360   SHA1_Update(&Context, SHA1_Pad2, 40);
    361   SHA1_Final(Digest, &Context);
    362 
    363   memcpy(InterimKey, Digest, SessionKeyLength);
    364 }
    365 
    366 #if 0
    367 static void
    368 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
    369         int LengthOfDesiredKey)
    370 {
    371   SHA_CTX Context;
    372   char Digest[SHA_DIGEST_LENGTH];
    373 
    374   SHA1_Init(&Context);
    375   SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
    376   SHA1_Update(&Context, SHA1_Pad1, 40);
    377   SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
    378   SHA1_Update(&Context, SHA1_Pad2, 40);
    379   SHA1_Final(Digest, &Context);
    380 
    381   memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
    382 }
    383 #endif
    384 
    385 /* passwordHash 16-bytes MD4 hashed password
    386    challenge    8-bytes peer CHAP challenge
    387    since passwordHash is in a 24-byte buffer, response is written in there */
    388 void
    389 mschap_NT(char *passwordHash, char *challenge)
    390 {
    391     u_char response[24];
    392 
    393     ChallengeResponse(challenge, passwordHash, response);
    394     memcpy(passwordHash, response, 24);
    395     passwordHash[24] = 1;		/* NT-style response */
    396 }
    397 
    398 void
    399 mschap_LANMan(char *digest, char *challenge, char *secret)
    400 {
    401   static u_char salt[] = "KGS!@#$%";	/* RASAPI32.dll */
    402   char SECRET[14], *ptr, *end;
    403   u_char hash[16];
    404 
    405   end = SECRET + sizeof SECRET;
    406   for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
    407     *ptr = toupper(*secret);
    408   if (ptr < end)
    409     memset(ptr, '\0', end - ptr);
    410 
    411   DesEncrypt(salt, SECRET, hash);
    412   DesEncrypt(salt, SECRET + 7, hash + 8);
    413 
    414   ChallengeResponse(challenge, hash, digest);
    415 }
    416