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 <sys/types.h> 27 28 #include <ctype.h> 29 #ifdef __FreeBSD__ 30 #include <openssl/des.h> 31 #include <sha.h> 32 #else 33 #include <stdlib.h> 34 #include <des.h> 35 #include <openssl/sha.h> 36 #endif 37 #include <md4.h> 38 #include <string.h> 39 40 #include "chap_ms.h" 41 42 /* 43 * Documentation & specifications: 44 * 45 * MS-CHAP (CHAP80) rfc2433 46 * MS-CHAP-V2 (CHAP81) rfc2759 47 * MPPE key management draft-ietf-pppext-mppe-keys-02.txt 48 */ 49 50 static char SHA1_Pad1[40] = 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 55 56 static char SHA1_Pad2[40] = 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 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2}; 61 62 /* unused, for documentation only */ 63 /* only NTResp is filled in for FreeBSD */ 64 struct MS_ChapResponse { 65 u_char LANManResp[24]; 66 u_char NTResp[24]; 67 u_char UseNT; /* If 1, ignore the LANMan response field */ 68 }; 69 70 static u_char 71 Get7Bits(u_char *input, int startBit) 72 { 73 register unsigned int word; 74 75 word = (unsigned)input[startBit / 8] << 8; 76 word |= (unsigned)input[startBit / 8 + 1]; 77 78 word >>= 15 - (startBit % 8 + 7); 79 80 return word & 0xFE; 81 } 82 83 /* IN 56 bit DES key missing parity bits 84 OUT 64 bit DES key with parity bits added */ 85 static void 86 MakeKey(u_char *key, u_char *des_key) 87 { 88 des_key[0] = Get7Bits(key, 0); 89 des_key[1] = Get7Bits(key, 7); 90 des_key[2] = Get7Bits(key, 14); 91 des_key[3] = Get7Bits(key, 21); 92 des_key[4] = Get7Bits(key, 28); 93 des_key[5] = Get7Bits(key, 35); 94 des_key[6] = Get7Bits(key, 42); 95 des_key[7] = Get7Bits(key, 49); 96 97 des_set_odd_parity((des_cblock *)des_key); 98 } 99 100 static void /* IN 8 octets IN 7 octest OUT 8 octets */ 101 DesEncrypt(u_char *clear, u_char *key, u_char *cipher) 102 { 103 des_cblock des_key; 104 des_key_schedule key_schedule; 105 106 MakeKey(key, des_key); 107 des_set_key(&des_key, key_schedule); 108 des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); 109 } 110 111 static void /* IN 8 octets IN 16 octets OUT 24 octets */ 112 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response) 113 { 114 char ZPasswordHash[21]; 115 116 memset(ZPasswordHash, '\0', sizeof ZPasswordHash); 117 memcpy(ZPasswordHash, pwHash, 16); 118 119 DesEncrypt(challenge, ZPasswordHash + 0, response + 0); 120 DesEncrypt(challenge, ZPasswordHash + 7, response + 8); 121 DesEncrypt(challenge, ZPasswordHash + 14, response + 16); 122 } 123 124 void 125 NtPasswordHash(char *key, int keylen, char *hash) 126 { 127 MD4_CTX MD4context; 128 129 MD4Init(&MD4context); 130 MD4Update(&MD4context, key, keylen); 131 MD4Final(hash, &MD4context); 132 } 133 134 void 135 HashNtPasswordHash(char *hash, char *hashhash) 136 { 137 MD4_CTX MD4context; 138 139 MD4Init(&MD4context); 140 MD4Update(&MD4context, hash, 16); 141 MD4Final(hashhash, &MD4context); 142 } 143 144 void 145 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, 146 char *UserName, int UserNameLen, char *Challenge) 147 { 148 SHA_CTX Context; 149 char Digest[SHA_DIGEST_LENGTH]; 150 char *Name; 151 152 Name = strrchr(UserName, '\\'); 153 if(NULL == Name) 154 Name = UserName; 155 else 156 Name++; 157 158 SHA1_Init(&Context); 159 160 SHA1_Update(&Context, PeerChallenge, 16); 161 SHA1_Update(&Context, AuthenticatorChallenge, 16); 162 SHA1_Update(&Context, UserName, UserNameLen); 163 164 SHA1_Final(Digest, &Context); 165 memcpy(Challenge, Digest, 8); 166 } 167 168 void 169 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge, 170 char *UserName, int UserNameLen, char *Password, 171 int PasswordLen, char *Response) 172 { 173 char Challenge[8]; 174 char PasswordHash[16]; 175 176 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, 177 Challenge); 178 NtPasswordHash(Password, PasswordLen, PasswordHash); 179 ChallengeResponse(Challenge, PasswordHash, Response); 180 } 181 182 #ifndef __FreeBSD__ 183 #define LENGTH 20 184 char * 185 SHA1_End(SHA_CTX *ctx, char *buf) 186 { 187 int i; 188 unsigned char digest[LENGTH]; 189 static const char hex[]="0123456789abcdef"; 190 191 if (!buf) 192 buf = malloc(2*LENGTH + 1); 193 if (!buf) 194 return 0; 195 SHA1_Final(digest, ctx); 196 for (i = 0; i < LENGTH; i++) { 197 buf[i+i] = hex[digest[i] >> 4]; 198 buf[i+i+1] = hex[digest[i] & 0x0f]; 199 } 200 buf[i+i] = '\0'; 201 return buf; 202 } 203 #endif 204 205 void 206 GenerateAuthenticatorResponse(char *Password, int PasswordLen, 207 char *NTResponse, char *PeerChallenge, 208 char *AuthenticatorChallenge, char *UserName, 209 int UserNameLen, char *AuthenticatorResponse) 210 { 211 SHA_CTX Context; 212 char PasswordHash[16]; 213 char PasswordHashHash[16]; 214 char Challenge[8]; 215 u_char Digest[SHA_DIGEST_LENGTH]; 216 int i; 217 218 /* 219 * "Magic" constants used in response generation 220 */ 221 char Magic1[39] = 222 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 223 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 224 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 225 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74}; 226 227 228 char Magic2[41] = 229 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 230 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 231 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 232 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 233 0x6E}; 234 /* 235 * Hash the password with MD4 236 */ 237 NtPasswordHash(Password, PasswordLen, PasswordHash); 238 /* 239 * Now hash the hash 240 */ 241 HashNtPasswordHash(PasswordHash, PasswordHashHash); 242 243 SHA1_Init(&Context); 244 SHA1_Update(&Context, PasswordHashHash, 16); 245 SHA1_Update(&Context, NTResponse, 24); 246 SHA1_Update(&Context, Magic1, 39); 247 SHA1_Final(Digest, &Context); 248 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, 249 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