1 /*- 2 * Copyright (c) 1997 Gabor Kincses <gabor@acm.org> 3 * 1997 - 2001 Brian Somers <brian@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.9.2.6 2002/09/01 02:12:23 brian Exp $ 30 */ 31 32 #include <ctype.h> 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #if defined(__DragonFly__) || defined(__NetBSD__) 36 #include <openssl/des.h> 37 #else 38 #include <des.h> 39 #endif 40 #include <openssl/sha.h> 41 #include <openssl/md4.h> 42 #include <string.h> 43 44 #include "chap_ms.h" 45 46 /* 47 * Documentation & specifications: 48 * 49 * MS-CHAP (CHAP80) rfc2433 50 * MS-CHAP-V2 (CHAP81) rfc2759 51 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt 52 */ 53 54 static char SHA1_Pad1[40] = 55 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 59 60 static char SHA1_Pad2[40] = 61 {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 62 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 63 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 64 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2}; 65 66 /* unused, for documentation only */ 67 /* only NTResp is filled in for FreeBSD */ 68 struct MS_ChapResponse { 69 u_char LANManResp[24]; 70 u_char NTResp[24]; 71 u_char UseNT; /* If 1, ignore the LANMan response field */ 72 }; 73 74 static u_char 75 Get7Bits(u_char *input, int startBit) 76 { 77 unsigned int word; 78 79 word = (unsigned)input[startBit / 8] << 8; 80 word |= (unsigned)input[startBit / 8 + 1]; 81 82 word >>= 15 - (startBit % 8 + 7); 83 84 return word & 0xFE; 85 } 86 87 /* IN 56 bit DES key missing parity bits 88 OUT 64 bit DES key with parity bits added */ 89 static void 90 MakeKey(u_char *key, u_char *des_key) 91 { 92 des_key[0] = Get7Bits(key, 0); 93 des_key[1] = Get7Bits(key, 7); 94 des_key[2] = Get7Bits(key, 14); 95 des_key[3] = Get7Bits(key, 21); 96 des_key[4] = Get7Bits(key, 28); 97 des_key[5] = Get7Bits(key, 35); 98 des_key[6] = Get7Bits(key, 42); 99 des_key[7] = Get7Bits(key, 49); 100 101 DES_set_odd_parity((DES_cblock *)des_key); 102 } 103 104 static void /* IN 8 octets IN 7 octest OUT 8 octets */ 105 DesEncrypt(u_char *clear, u_char *key, u_char *cipher) 106 { 107 DES_cblock des_key; 108 DES_key_schedule key_schedule; 109 110 MakeKey(key, des_key); 111 DES_set_key(&des_key, &key_schedule); 112 DES_ecb_encrypt((DES_cblock *)clear, (DES_cblock *)cipher, &key_schedule, 1); 113 } 114 115 static void /* IN 8 octets IN 16 octets OUT 24 octets */ 116 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response) 117 { 118 char ZPasswordHash[21]; 119 120 memset(ZPasswordHash, '\0', sizeof ZPasswordHash); 121 memcpy(ZPasswordHash, pwHash, 16); 122 123 DesEncrypt(challenge, ZPasswordHash + 0, response + 0); 124 DesEncrypt(challenge, ZPasswordHash + 7, response + 8); 125 DesEncrypt(challenge, ZPasswordHash + 14, response + 16); 126 } 127 128 void 129 NtPasswordHash(char *key, int keylen, char *hash) 130 { 131 MD4_CTX MD4context; 132 133 MD4_Init(&MD4context); 134 MD4_Update(&MD4context, key, keylen); 135 MD4_Final(hash, &MD4context); 136 } 137 138 void 139 HashNtPasswordHash(char *hash, char *hashhash) 140 { 141 MD4_CTX MD4context; 142 143 MD4_Init(&MD4context); 144 MD4_Update(&MD4context, hash, 16); 145 MD4_Final(hashhash, &MD4context); 146 } 147 148 static void 149 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, 150 char *UserName, char *Challenge) 151 { 152 SHA_CTX Context; 153 char Digest[SHA_DIGEST_LENGTH]; 154 char *Name; 155 156 Name = strrchr(UserName, '\\'); 157 if(NULL == Name) 158 Name = UserName; 159 else 160 Name++; 161 162 SHA1_Init(&Context); 163 164 SHA1_Update(&Context, PeerChallenge, 16); 165 SHA1_Update(&Context, AuthenticatorChallenge, 16); 166 SHA1_Update(&Context, Name, strlen(Name)); 167 168 SHA1_Final(Digest, &Context); 169 memcpy(Challenge, Digest, 8); 170 } 171 172 void 173 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge, 174 char *UserName, char *Password, 175 int PasswordLen, char *Response) 176 { 177 char Challenge[8]; 178 char PasswordHash[16]; 179 180 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge); 181 NtPasswordHash(Password, PasswordLen, PasswordHash); 182 ChallengeResponse(Challenge, PasswordHash, Response); 183 } 184 185 #define LENGTH 20 186 static char * 187 SHA1_End(SHA_CTX *ctx, char *buf) 188 { 189 int i; 190 unsigned char digest[LENGTH]; 191 static const char hex[]="0123456789abcdef"; 192 193 if (!buf) 194 buf = malloc(2*LENGTH + 1); 195 if (!buf) 196 return 0; 197 SHA1_Final(digest, ctx); 198 for (i = 0; i < LENGTH; i++) { 199 buf[i+i] = hex[digest[i] >> 4]; 200 buf[i+i+1] = hex[digest[i] & 0x0f]; 201 } 202 buf[i+i] = '\0'; 203 return buf; 204 } 205 206 void 207 GenerateAuthenticatorResponse(char *Password, int PasswordLen, 208 char *NTResponse, char *PeerChallenge, 209 char *AuthenticatorChallenge, char *UserName, 210 char *AuthenticatorResponse) 211 { 212 SHA_CTX Context; 213 char PasswordHash[16]; 214 char PasswordHashHash[16]; 215 char Challenge[8]; 216 u_char Digest[SHA_DIGEST_LENGTH]; 217 int i; 218 219 /* 220 * "Magic" constants used in response generation 221 */ 222 char Magic1[39] = 223 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 224 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 225 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 226 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; 227 228 229 char Magic2[41] = 230 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 231 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 232 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 233 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 234 0x6E}; 235 /* 236 * Hash the password with MD4 237 */ 238 NtPasswordHash(Password, PasswordLen, PasswordHash); 239 /* 240 * Now hash the hash 241 */ 242 HashNtPasswordHash(PasswordHash, PasswordHashHash); 243 244 SHA1_Init(&Context); 245 SHA1_Update(&Context, PasswordHashHash, 16); 246 SHA1_Update(&Context, NTResponse, 24); 247 SHA1_Update(&Context, Magic1, 39); 248 SHA1_Final(Digest, &Context); 249 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge); 250 SHA1_Init(&Context); 251 SHA1_Update(&Context, Digest, 20); 252 SHA1_Update(&Context, Challenge, 8); 253 SHA1_Update(&Context, Magic2, 41); 254 255 /* 256 * Encode the value of 'Digest' as "S=" followed by 257 * 40 ASCII hexadecimal digits and return it in 258 * AuthenticatorResponse. 259 * For example, 260 * "S=0123456789ABCDEF0123456789ABCDEF01234567" 261 */ 262 AuthenticatorResponse[0] = 'S'; 263 AuthenticatorResponse[1] = '='; 264 SHA1_End(&Context, AuthenticatorResponse + 2); 265 for (i=2; i<42; i++) 266 AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]); 267 268 } 269 270 void 271 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey) 272 { 273 char Digest[SHA_DIGEST_LENGTH]; 274 SHA_CTX Context; 275 static char Magic1[27] = 276 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 277 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 278 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}; 279 280 SHA1_Init(&Context); 281 SHA1_Update(&Context, PasswordHashHash, 16); 282 SHA1_Update(&Context, NTResponse, 24); 283 SHA1_Update(&Context, Magic1, 27); 284 SHA1_Final(Digest, &Context); 285 memcpy(MasterKey, Digest, 16); 286 } 287 288 void 289 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength, 290 int IsSend, int IsServer) 291 { 292 char Digest[SHA_DIGEST_LENGTH]; 293 SHA_CTX Context; 294 char *s; 295 296 static char Magic2[84] = 297 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 298 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 299 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 300 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 301 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 302 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 303 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 304 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 305 0x6b, 0x65, 0x79, 0x2e}; 306 307 static char Magic3[84] = 308 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 309 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 310 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 311 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 312 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 313 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 314 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 315 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 316 0x6b, 0x65, 0x79, 0x2e}; 317 318 if (IsSend) { 319 if (IsServer) { 320 s = Magic3; 321 } else { 322 s = Magic2; 323 } 324 } else { 325 if (IsServer) { 326 s = Magic2; 327 } else { 328 s = Magic3; 329 } 330 } 331 332 SHA1_Init(&Context); 333 SHA1_Update(&Context, MasterKey, 16); 334 SHA1_Update(&Context, SHA1_Pad1, 40); 335 SHA1_Update(&Context, s, 84); 336 SHA1_Update(&Context, SHA1_Pad2, 40); 337 SHA1_Final(Digest, &Context); 338 339 memcpy(SessionKey, Digest, SessionKeyLength); 340 } 341 342 void 343 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength, 344 char *InterimKey) 345 { 346 SHA_CTX Context; 347 char Digest[SHA_DIGEST_LENGTH]; 348 349 SHA1_Init(&Context); 350 SHA1_Update(&Context, StartKey, SessionKeyLength); 351 SHA1_Update(&Context, SHA1_Pad1, 40); 352 SHA1_Update(&Context, SessionKey, SessionKeyLength); 353 SHA1_Update(&Context, SHA1_Pad2, 40); 354 SHA1_Final(Digest, &Context); 355 356 memcpy(InterimKey, Digest, SessionKeyLength); 357 } 358 359 #if 0 360 static void 361 Get_Key(char *InitialSessionKey, char *CurrentSessionKey, 362 int LengthOfDesiredKey) 363 { 364 SHA_CTX Context; 365 char Digest[SHA_DIGEST_LENGTH]; 366 367 SHA1_Init(&Context); 368 SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey); 369 SHA1_Update(&Context, SHA1_Pad1, 40); 370 SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey); 371 SHA1_Update(&Context, SHA1_Pad2, 40); 372 SHA1_Final(Digest, &Context); 373 374 memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey); 375 } 376 #endif 377 378 /* passwordHash 16-bytes MD4 hashed password 379 challenge 8-bytes peer CHAP challenge 380 since passwordHash is in a 24-byte buffer, response is written in there */ 381 void 382 mschap_NT(char *passwordHash, char *challenge) 383 { 384 u_char response[24]; 385 386 ChallengeResponse(challenge, passwordHash, response); 387 memcpy(passwordHash, response, 24); 388 passwordHash[24] = 1; /* NT-style response */ 389 } 390 391 void 392 mschap_LANMan(char *digest, char *challenge, char *secret) 393 { 394 static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */ 395 char SECRET[14], *ptr, *end; 396 u_char hash[16]; 397 398 end = SECRET + sizeof SECRET; 399 for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) 400 *ptr = toupper(*secret); 401 if (ptr < end) 402 memset(ptr, '\0', end - ptr); 403 404 DesEncrypt(salt, SECRET, hash); 405 DesEncrypt(salt, SECRET + 7, hash + 8); 406 407 ChallengeResponse(challenge, hash, digest); 408 } 409