/* * msoft.c * * Rewritten by Archie Cobbs * Copyright (c) 1998-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" #include "msoft.h" #ifdef ENCRYPTION_MPPE #include #endif #include #include /* * This stuff is described in: * * MS-CHAPv1 * http://www.es.net/pub/rfcs/rfc2433.txt * * MS-CHAPv2 * http://www.es.net/pub/rfcs/rfc2759.txt * * Deriving MPPE keys from MS-CHAPv1 and MS-CHAPv2 * http://www.es.net/pub/rfcs/rfc3079.txt */ /* Magic constants */ #define MS_MAGIC_1 "This is the MPPE Master Key" #define MS_MAGIC_2 "On the client side, this is the send key;" \ " on the server side, it is the receive key." #define MS_MAGIC_3 "On the client side, this is the receive key;" \ " on the server side, it is the send key." #define MS_AR_MAGIC_1 "Magic server to client signing constant" #define MS_AR_MAGIC_2 "Pad to make it do more than one iteration" /* * INTERNAL FUNCTIONS */ static void ChallengeResponse(const u_char *chal, const char *pwHash, u_char *hash); static void DesEncrypt(const u_char *clear, u_char *key0, u_char *cypher); static void ChallengeHash(const u_char *peerchal, const u_char *authchal, const char *username, u_char *hash); /* * LMPasswordHash() * * password ASCII password * hash 16 byte output LanManager hash */ void LMPasswordHash(const char *password, u_char *hash) { const char *const clear = "KGS!@#$%%"; u_char up[14]; /* upper case password */ int k; memset(&up, 0, sizeof(up)); for (k = 0; k < sizeof(up) && password[k]; k++) up[k] = toupper(password[k]); DesEncrypt(clear, &up[0], &hash[0]); DesEncrypt(clear, &up[7], &hash[8]); } /* * NTPasswordHash() * * password ASCII (NOT Unicode) password * hash 16 byte output NT hash */ void NTPasswordHash(const char *password, u_char *hash) { u_int16_t unipw[128]; int unipwLen; MD4_CTX md4ctx; const char *s; /* Convert password to Unicode */ for (unipwLen = 0, s = password; unipwLen < sizeof(unipw) / 2 && *s; s++) unipw[unipwLen++] = htons(*s << 8); /* Compute MD4 of Unicode password */ MD4_Init(&md4ctx); MD4_Update(&md4ctx, (u_char *) unipw, unipwLen * sizeof(*unipw)); MD4_Final(hash, &md4ctx); } /* * NTChallengeResponse() * * chal 8 byte challenge * password ASCII (NOT Unicode) password * hash 24 byte response */ void NTChallengeResponse(const u_char *chal, const char *password, u_char *hash) { u_char pwHash[16]; NTPasswordHash(password, pwHash); ChallengeResponse(chal, pwHash, hash); } /* * ChallengeResponse() * * chal 8 byte challenge * pwHash 16 byte password hash * hash 24 byte response */ static void ChallengeResponse(const u_char *chal, const char *pwHash, u_char *hash) { u_char buf[21]; int k; memset(&buf, 0, sizeof(buf)); memcpy(buf, pwHash, 16); /* Use DES to hash the hash */ for (k = 0; k < 3; k++) { u_char *const key = &buf[k * 7]; u_char *const output = &hash[k * 8]; DesEncrypt(chal, key, output); } } /* * DesEncrypt() * * clear 8 byte cleartext * key 7 byte key * cypher 8 byte cyphertext */ static void DesEncrypt(const u_char *clear, u_char *key0, u_char *cypher) { des_key_schedule ks; u_char key[8]; /* Create DES key */ key[0] = key0[0] & 0xfe; key[1] = (key0[0] << 7) | (key0[1] >> 1); key[2] = (key0[1] << 6) | (key0[2] >> 2); key[3] = (key0[2] << 5) | (key0[3] >> 3); key[4] = (key0[3] << 4) | (key0[4] >> 4); key[5] = (key0[4] << 3) | (key0[5] >> 5); key[6] = (key0[5] << 2) | (key0[6] >> 6); key[7] = key0[6] << 1; des_set_key((des_cblock *) key, ks); /* Encrypt using key */ des_ecb_encrypt((des_cblock *) clear, (des_cblock *) cypher, ks, 1); } #ifdef ENCRYPTION_MPPE /* * MsoftGetStartKey() */ void MsoftGetStartKey(u_char *chal, u_char *h) { SHA_CTX c; u_char hash[20]; SHA1_Init(&c); SHA1_Update(&c, h, 16); SHA1_Update(&c, h, 16); SHA1_Update(&c, chal, 8); SHA1_Final(hash, &c); memcpy(h, hash, 16); } #endif /* * GenerateNTResponse() * * authchal 16 byte authenticator challenge * peerchal 16 byte peer challenge * username ASCII username * password ASCII (NOT Unicode) password * hash 24 byte response */ void GenerateNTResponse(const u_char *authchal, const u_char *peerchal, const char *username, const char *password, u_char *hash) { u_char chal[8]; u_char pwHash[16]; ChallengeHash(peerchal, authchal, username, chal); NTPasswordHash(password, pwHash); ChallengeResponse(chal, pwHash, hash); } /* * ChallengeHash() * * peerchal 16 byte peer challenge * authchal 16 byte authenticator challenge * username ASCII username * hash 8 byte response */ static void ChallengeHash(const u_char *peerchal, const u_char *authchal, const char *username, u_char *hash) { SHA_CTX c; u_char digest[20]; SHA1_Init(&c); SHA1_Update(&c, peerchal, 16); SHA1_Update(&c, authchal, 16); SHA1_Update(&c, username, strlen(username)); SHA1_Final(digest, &c); memcpy(hash, digest, 8); } /* * Generate response to MS-CHAPv2 piggy-backed challenge. * * "authresp" must point to a 20 byte buffer. */ void GenerateAuthenticatorResponse(const char *password, const u_char *ntresp, const u_char *peerchal, const u_char *authchal, const char *username, u_char *authresp) { u_char hash[16]; u_char digest[SHA_DIGEST_LENGTH]; u_char chal[8]; MD4_CTX md4ctx; SHA_CTX shactx; NTPasswordHash(password, hash); MD4_Init(&md4ctx); MD4_Update(&md4ctx, hash, 16); MD4_Final(hash, &md4ctx); SHA1_Init(&shactx); SHA1_Update(&shactx, hash, 16); SHA1_Update(&shactx, ntresp, 24); SHA1_Update(&shactx, MS_AR_MAGIC_1, 39); SHA1_Final(digest, &shactx); ChallengeHash(peerchal, authchal, username, chal); SHA1_Init(&shactx); SHA1_Update(&shactx, digest, sizeof(digest)); SHA1_Update(&shactx, chal, 8); SHA1_Update(&shactx, MS_AR_MAGIC_2, 41); SHA1_Final(authresp, &shactx); } #ifdef ENCRYPTION_MPPE /* * MsoftGetMasterKey() */ void MsoftGetMasterKey(u_char *resp, u_char *h) { SHA_CTX c; u_char hash[20]; SHA1_Init(&c); SHA1_Update(&c, h, 16); SHA1_Update(&c, resp, 24); SHA1_Update(&c, MS_MAGIC_1, 27); SHA1_Final(hash, &c); memcpy(h, hash, 16); } /* * MsoftGetAsymetricStartKey() */ void MsoftGetAsymetricStartKey(u_char *h, int server_recv) { SHA_CTX c; u_char pad[40]; u_char hash[20]; SHA1_Init(&c); SHA1_Update(&c, h, 16); memset(pad, 0x00, sizeof(pad)); SHA1_Update(&c, pad, sizeof(pad)); SHA1_Update(&c, server_recv ? MS_MAGIC_2 : MS_MAGIC_3, 84); memset(pad, 0xf2, sizeof(pad)); SHA1_Update(&c, pad, sizeof(pad)); SHA1_Final(hash, &c); memcpy(h, hash, 16); } #endif