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