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