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