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.4 2004/03/27 01:39:13 cpressey 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 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 static void 155 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge, 156 char *UserName, 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, char *Password, 181 int PasswordLen, char *Response) 182 { 183 char Challenge[8]; 184 char PasswordHash[16]; 185 186 ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge); 187 NtPasswordHash(Password, PasswordLen, PasswordHash); 188 ChallengeResponse(Challenge, PasswordHash, Response); 189 } 190 191 #ifndef __DragonFly__ 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 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, Challenge); 258 SHA1_Init(&Context); 259 SHA1_Update(&Context, Digest, 20); 260 SHA1_Update(&Context, Challenge, 8); 261 SHA1_Update(&Context, Magic2, 41); 262 263 /* 264 * Encode the value of 'Digest' as "S=" followed by 265 * 40 ASCII hexadecimal digits and return it in 266 * AuthenticatorResponse. 267 * For example, 268 * "S=0123456789ABCDEF0123456789ABCDEF01234567" 269 */ 270 AuthenticatorResponse[0] = 'S'; 271 AuthenticatorResponse[1] = '='; 272 SHA1_End(&Context, AuthenticatorResponse + 2); 273 for (i=2; i<42; i++) 274 AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]); 275 276 } 277 278 void 279 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey) 280 { 281 char Digest[SHA_DIGEST_LENGTH]; 282 SHA_CTX Context; 283 static char Magic1[27] = 284 {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 285 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 286 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79}; 287 288 SHA1_Init(&Context); 289 SHA1_Update(&Context, PasswordHashHash, 16); 290 SHA1_Update(&Context, NTResponse, 24); 291 SHA1_Update(&Context, Magic1, 27); 292 SHA1_Final(Digest, &Context); 293 memcpy(MasterKey, Digest, 16); 294 } 295 296 void 297 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength, 298 int IsSend, int IsServer) 299 { 300 char Digest[SHA_DIGEST_LENGTH]; 301 SHA_CTX Context; 302 char *s; 303 304 static char Magic2[84] = 305 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 306 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 307 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 308 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 309 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 310 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 311 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 312 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 313 0x6b, 0x65, 0x79, 0x2e}; 314 315 static char Magic3[84] = 316 {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 317 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 318 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 319 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 320 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 321 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 322 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 323 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 324 0x6b, 0x65, 0x79, 0x2e}; 325 326 if (IsSend) { 327 if (IsServer) { 328 s = Magic3; 329 } else { 330 s = Magic2; 331 } 332 } else { 333 if (IsServer) { 334 s = Magic2; 335 } else { 336 s = Magic3; 337 } 338 } 339 340 SHA1_Init(&Context); 341 SHA1_Update(&Context, MasterKey, 16); 342 SHA1_Update(&Context, SHA1_Pad1, 40); 343 SHA1_Update(&Context, s, 84); 344 SHA1_Update(&Context, SHA1_Pad2, 40); 345 SHA1_Final(Digest, &Context); 346 347 memcpy(SessionKey, Digest, SessionKeyLength); 348 } 349 350 void 351 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength, 352 char *InterimKey) 353 { 354 SHA_CTX Context; 355 char Digest[SHA_DIGEST_LENGTH]; 356 357 SHA1_Init(&Context); 358 SHA1_Update(&Context, StartKey, SessionKeyLength); 359 SHA1_Update(&Context, SHA1_Pad1, 40); 360 SHA1_Update(&Context, SessionKey, SessionKeyLength); 361 SHA1_Update(&Context, SHA1_Pad2, 40); 362 SHA1_Final(Digest, &Context); 363 364 memcpy(InterimKey, Digest, SessionKeyLength); 365 } 366 367 #if 0 368 static void 369 Get_Key(char *InitialSessionKey, char *CurrentSessionKey, 370 int LengthOfDesiredKey) 371 { 372 SHA_CTX Context; 373 char Digest[SHA_DIGEST_LENGTH]; 374 375 SHA1_Init(&Context); 376 SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey); 377 SHA1_Update(&Context, SHA1_Pad1, 40); 378 SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey); 379 SHA1_Update(&Context, SHA1_Pad2, 40); 380 SHA1_Final(Digest, &Context); 381 382 memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey); 383 } 384 #endif 385 386 /* passwordHash 16-bytes MD4 hashed password 387 challenge 8-bytes peer CHAP challenge 388 since passwordHash is in a 24-byte buffer, response is written in there */ 389 void 390 mschap_NT(char *passwordHash, char *challenge) 391 { 392 u_char response[24]; 393 394 ChallengeResponse(challenge, passwordHash, response); 395 memcpy(passwordHash, response, 24); 396 passwordHash[24] = 1; /* NT-style response */ 397 } 398 399 void 400 mschap_LANMan(char *digest, char *challenge, char *secret) 401 { 402 static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */ 403 char SECRET[14], *ptr, *end; 404 u_char hash[16]; 405 406 end = SECRET + sizeof SECRET; 407 for (ptr = SECRET; *secret && ptr < end; ptr++, secret++) 408 *ptr = toupper(*secret); 409 if (ptr < end) 410 memset(ptr, '\0', end - ptr); 411 412 DesEncrypt(salt, SECRET, hash); 413 DesEncrypt(salt, SECRET + 7, hash + 8); 414 415 ChallengeResponse(challenge, hash, digest); 416 } 417