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$ 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 void 154 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, 155 char *UserName, int UserNameLen, 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, int UserNameLen, char *Password, 180 int PasswordLen, char *Response) 181 { 182 char Challenge[8]; 183 char PasswordHash[16]; 184 185 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, 186 Challenge); 187 NtPasswordHash(Password, PasswordLen, PasswordHash); 188 ChallengeResponse(Challenge, PasswordHash, Response); 189 } 190 191 #ifndef __FreeBSD__ 192 #define LENGTH 20 193 static char * 194 SHA1_End(SHA_CTX *ctx, char *buf) 195 { 196 int i; 197 unsigned char digest[LENGTH]; 198 static const char hex[]="0123456789abcdef"; 199 200 if (!buf) 201 buf = malloc(2*LENGTH + 1); 202 if (!buf) 203 return 0; 204 SHA1_Final(digest, ctx); 205 for (i = 0; i < LENGTH; i++) { 206 buf[i+i] = hex[digest[i] >> 4]; 207 buf[i+i+1] = hex[digest[i] & 0x0f]; 208 } 209 buf[i+i] = '\0'; 210 return buf; 211 } 212 #endif 213 214 void 215 GenerateAuthenticatorResponse(char *Password, int PasswordLen, 216 char *NTResponse, char *PeerChallenge, 217 char *AuthenticatorChallenge, char *UserName, 218 int UserNameLen, char *AuthenticatorResponse) 219 { 220 SHA_CTX Context; 221 char PasswordHash[16]; 222 char PasswordHashHash[16]; 223 char Challenge[8]; 224 u_char Digest[SHA_DIGEST_LENGTH]; 225 int i; 226 227 /* 228 * "Magic" constants used in response generation 229 */ 230 char Magic1[39] = 231 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 232 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 233 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 234 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; 235 236 237 char Magic2[41] = 238 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 239 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 240 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 241 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 242 0x6E}; 243 /* 244 * Hash the password with MD4 245 */ 246 NtPasswordHash(Password, PasswordLen, PasswordHash); 247 /* 248 * Now hash the hash 249 */ 250 HashNtPasswordHash(PasswordHash, PasswordHashHash); 251 252 SHA1_Init(&Context); 253 SHA1_Update(&Context, PasswordHashHash, 16); 254 SHA1_Update(&Context, NTResponse, 24); 255 SHA1_Update(&Context, Magic1, 39); 256 SHA1_Final(Digest, &Context); 257 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, 258 Challenge); 259 SHA1_Init(&Context); 260 SHA1_Update(&Context, Digest, 20); 261 SHA1_Update(&Context, Challenge, 8); 262 SHA1_Update(&Context, Magic2, 41); 263 264 /* 265 * Encode the value of 'Digest' as "S=" followed by 266 * 40 ASCII hexadecimal digits and return it in 267 * AuthenticatorResponse. 268 * For example, 269 * "S=0123456789ABCDEF0123456789ABCDEF01234567" 270 */ 271 AuthenticatorResponse[0] = 'S'; 272 AuthenticatorResponse[1] = '='; 273 SHA1_End(&Context, AuthenticatorResponse + 2); 274 for (i=2; i<42; i++) 275 AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]); 276 277 } 278 279 void 280 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey) 281 { 282 char Digest[SHA_DIGEST_LENGTH]; 283 SHA_CTX Context; 284 static char Magic1[27] = 285 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 286 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 287 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}; 288 289 SHA1_Init(&Context); 290 SHA1_Update(&Context, PasswordHashHash, 16); 291 SHA1_Update(&Context, NTResponse, 24); 292 SHA1_Update(&Context, Magic1, 27); 293 SHA1_Final(Digest, &Context); 294 memcpy(MasterKey, Digest, 16); 295 } 296 297 void 298 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength, 299 int IsSend, int IsServer) 300 { 301 char Digest[SHA_DIGEST_LENGTH]; 302 SHA_CTX Context; 303 char *s; 304 305 static char Magic2[84] = 306 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 307 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 308 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 309 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 310 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 311 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 312 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 313 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 314 0x6b, 0x65, 0x79, 0x2e}; 315 316 static char Magic3[84] = 317 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 318 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 319 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 320 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 321 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 322 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 323 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 324 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 325 0x6b, 0x65, 0x79, 0x2e}; 326 327 if (IsSend) { 328 if (IsServer) { 329 s = Magic3; 330 } else { 331 s = Magic2; 332 } 333 } else { 334 if (IsServer) { 335 s = Magic2; 336 } else { 337 s = Magic3; 338 } 339 } 340 341 SHA1_Init(&Context); 342 SHA1_Update(&Context, MasterKey, 16); 343 SHA1_Update(&Context, SHA1_Pad1, 40); 344 SHA1_Update(&Context, s, 84); 345 SHA1_Update(&Context, SHA1_Pad2, 40); 346 SHA1_Final(Digest, &Context); 347 348 memcpy(SessionKey, Digest, SessionKeyLength); 349 } 350 351 void 352 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength, 353 char *InterimKey) 354 { 355 SHA_CTX Context; 356 char Digest[SHA_DIGEST_LENGTH]; 357 358 SHA1_Init(&Context); 359 SHA1_Update(&Context, StartKey, SessionKeyLength); 360 SHA1_Update(&Context, SHA1_Pad1, 40); 361 SHA1_Update(&Context, SessionKey, SessionKeyLength); 362 SHA1_Update(&Context, SHA1_Pad2, 40); 363 SHA1_Final(Digest, &Context); 364 365 memcpy(InterimKey, Digest, SessionKeyLength); 366 } 367 368 #if 0 369 static void 370 Get_Key(char *InitialSessionKey, char *CurrentSessionKey, 371 int LengthOfDesiredKey) 372 { 373 SHA_CTX Context; 374 char Digest[SHA_DIGEST_LENGTH]; 375 376 SHA1_Init(&Context); 377 SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey); 378 SHA1_Update(&Context, SHA1_Pad1, 40); 379 SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey); 380 SHA1_Update(&Context, SHA1_Pad2, 40); 381 SHA1_Final(Digest, &Context); 382 383 memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey); 384 } 385 #endif 386 387 /* passwordHash 16-bytes MD4 hashed password 388 challenge 8-bytes peer CHAP challenge 389 since passwordHash is in a 24-byte buffer, response is written in there */ 390 void 391 mschap_NT(char *passwordHash, char *challenge) 392 { 393 u_char response[24]; 394 395 ChallengeResponse(challenge, passwordHash, response); 396 memcpy(passwordHash, response, 24); 397 passwordHash[24] = 1; /* NT-style response */ 398 } 399 400 void 401 mschap_LANMan(char *digest, char *challenge, char *secret) 402 { 403 static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */ 404 char SECRET[14], *ptr, *end; 405 u_char hash[16]; 406 407 end = SECRET + sizeof SECRET; 408 for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) 409 *ptr = toupper(*secret); 410 if (ptr < end) 411 memset(ptr, '\0', end - ptr); 412 413 DesEncrypt(salt, SECRET, hash); 414 DesEncrypt(salt, SECRET + 7, hash + 8); 415 416 ChallengeResponse(challenge, hash, digest); 417 } 418