#include "stdafx.h" #include "auth.h" #include "md5.h" const CHAR g_cszADVAPI32DllName[] = "ADVAPI32.DLL"; const CHAR g_cszCryptAcquireContextA[] = "CryptAcquireContextA"; const CHAR g_cszCryptCreateHash[] = "CryptCreateHash"; const CHAR g_cszCryptHashData[] = "CryptHashData"; const CHAR g_cszCryptGetHashParam[] = "CryptGetHashParam"; const CHAR g_cszCryptDestroyHash[] = "CryptDestroyHash"; const CHAR g_cszCryptReleaseContext[] = "CryptReleaseContext"; const CHAR g_rgchHexNumMap[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; const int MD5_HASH_LEN = 16; void hmac_md5( unsigned char* text, /* pointer to data stream */ int text_len, /* length of data stream */ unsigned char* key, /* pointer to authentication key */ int key_len, /* length of authentication key */ BYTE digest[16]) /* caller digest to be filled in */ { MD5_CTX context; memset(&context, 0, sizeof(context)); unsigned char k_ipad[65]; /* inner padding - * key XORd with ipad */ unsigned char k_opad[65]; /* outer padding - * key XORd with opad */ int i; /* if key is longer than 64 bytes reset it to key=MD5(key) */ if (key_len > 64) { MD5_CTX tctx; memset(&tctx, 0, sizeof(tctx)); MD5Init(&tctx); MD5Update(&tctx, key, key_len); MD5Final(&tctx); key = tctx.digest; key_len = 16; } /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in pads */ ZeroMemory( k_ipad, sizeof k_ipad); ZeroMemory( k_opad, sizeof k_opad); CopyMemory( k_ipad, key, key_len); CopyMemory( k_opad, key, key_len); /* XOR key with ipad and opad values */ for (i=0; i<64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* * perform inner MD5 */ MD5Init(&context); /* init context for 1st * pass */ MD5Update(&context, k_ipad, 64); /* start with inner pad */ MD5Update(&context, text, text_len); /* then text of datagram */ MD5Final(&context); /* finish up 1st pass */ CopyMemory(digest, context.digest, 16); /* * perform outer MD5 */ MD5Init(&context); /* init context for 2nd * pass */ MD5Update(&context, k_opad, 64); /* start with outer pad */ MD5Update(&context, digest, 16); /* then results of 1st * hash */ MD5Final(&context); /* finish up 2nd pass */ CopyMemory(digest, context.digest, 16); } //------------------------------------------------------------------------------------ // // Initialize the static class members. // //------------------------------------------------------------------------------------ CAuthentication* CAuthentication::m_spAuthentication = NULL; PSTR CAuthentication::GetHMACMD5Result(PSTR pszChallengeInfo, PSTR pszPassword) { MD5_CTX MD5Buffer; memset(&MD5Buffer, 0, sizeof(MD5Buffer)); MD5Init(&MD5Buffer); MD5Update(&MD5Buffer, (const unsigned char*)pszPassword, lstrlenA(pszPassword)); MD5Final(&MD5Buffer); BYTE pbHash[16]; PBYTE pbHexHash = NULL; // The MD5 result in hex string format pbHexHash = new BYTE[MD5DIGESTLEN * 2 + 1]; if (pbHexHash) { hmac_md5((unsigned char *) pszChallengeInfo, lstrlenA(pszChallengeInfo), MD5Buffer.digest, sizeof(MD5Buffer.digest), pbHash); PBYTE pCurrent = pbHexHash; // Convert the hash data to hex string. for (int i = 0; i < MD5DIGESTLEN; i++) { *pCurrent++ = g_rgchHexNumMap[pbHash[i]/16]; *pCurrent++ = g_rgchHexNumMap[pbHash[i]%16]; } *pCurrent = '\0'; } return (PSTR) pbHexHash; } //------------------------------------------------------------------------------------ // // Method: CAuthentication::GetMD5Key() // // Synopsis: Construct the MD5 hash key based on the ChallengeInfo and password. // // Append the password to the ChallengeInfo. // //------------------------------------------------------------------------------------ PSTR CAuthentication::GetMD5Key(PSTR pszChallengeInfo, PSTR pszPassword) { int cbChallengeInfo = lstrlenA(pszChallengeInfo); int cbPassword = lstrlenA(pszPassword); PBYTE pbData = new BYTE[cbChallengeInfo + cbPassword + 1]; if (!pbData) { //WARNING_OUT(("CAuthentication::GetMD5Key> Out of memory")); return NULL; } PBYTE pCurrent = pbData; ::CopyMemory(pCurrent, pszChallengeInfo, cbChallengeInfo); pCurrent += cbChallengeInfo; ::CopyMemory(pCurrent, pszPassword, cbPassword); pCurrent += cbPassword; *pCurrent = '\0'; return (PSTR)pbData; } //------------------------------------------------------------------------------------ // // Method: CAuthentication::GetMD5Result() // // Synposis: Compute the MD5 hash result based on the clear text. // //------------------------------------------------------------------------------------ PSTR CAuthentication::GetMD5Result(PCSTR pszClearText) { PBYTE pbHexHash = NULL; if (pszClearText) { MD5_CTX MD5Buffer; MD5Init(&MD5Buffer); MD5Update(&MD5Buffer, (const unsigned char*)pszClearText, lstrlenA(pszClearText)); MD5Final(&MD5Buffer); PBYTE pbHash = MD5Buffer.digest; pbHexHash = new BYTE[MD5DIGESTLEN * 2 + 1]; if (pbHexHash) { PBYTE pCurrent = pbHexHash; // Convert the hash data to hex string. for (int i = 0; i < MD5DIGESTLEN; i++) { *pCurrent++ = g_rgchHexNumMap[pbHash[i]/16]; *pCurrent++ = g_rgchHexNumMap[pbHash[i]%16]; } *pCurrent = '\0'; } else { //WARNING_OUT(("CAuthentication::GetMD5Result> Out of memory")); } } return (PSTR)pbHexHash; } //------------------------------------------------------------------------------------ // // Method: CAuthentication::GetMD5Result() // // Synopsis: Compute the MD5 hash result based on the ChallengeInfo and password. // //------------------------------------------------------------------------------------ PSTR CAuthentication::GetMD5Result(PSTR pszChallengeInfo, PSTR pszPassword) { PSTR pbHexHash = NULL; // The MD5 result in hex string format PSTR pMD5Key = GetMD5Key(pszChallengeInfo, pszPassword); pbHexHash = GetMD5Result(pMD5Key); delete pMD5Key; return pbHexHash; }