I have the following, seemingly simple, piece of PHP code which is part of a CHAP implementation that I need to incorporate into a C++ project:
$response = md5("\0" . hash('sha256', $password) . pack('H32', $challenge);
This is what I have so far:
// should do what hash('sha256', $password) does
string shaString(const string str)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)hash[i];
}
return ss.str();
}
// should do the rest
string md5String(const string password, const string challenge)
{
int clen = challenge.length() / 2; // should be half length of hex values
int plen = password.length() + 1; // add one for null terminating string
int tlen = clen + plen + 1;
unsigned char *buffer = (unsigned char *) malloc(tlen);
unsigned short buf;
const char *pstr = password.c_str();
unsigned char digest[MD5_DIGEST_LENGTH];
MD5_CTX md5;
memset(buffer, 0, tlen);
// skip the first byte as we need to start with \0,
// copy password starting at second byte
memcpy(buffer + 1, pstr, plen);
int start = plen + 1;
// should be equivalent to pack('H32', $challenge)
for (int j = 0; j < clen; j++) {
if (scanf((challenge.substr(j * 2, 2)).c_str(), "%hx", &buf) < 1)
break;
buffer[start + j] = (unsigned char) buf;
}
MD5_Init(&md5); // md5 what we got so far
MD5_Update(&md5, buffer, tlen);
MD5_Final(digest, &md5);
stringstream ss;
for (int i = 0; i < MD5_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)digest[i];
}
free(buffer);
return ss.str();
}
string response = md5String(shaString(password.c_str()), challenge.c_str());
The code runs and generates the string, but the value is incorrect, I have been unable to determine why exactly, since it's a cryptographic hash, it's hard to compare results.
I think I'm doing something stupid somewhere, been battling with this for hours. Any suggestions would be greatly appreciated. My goal is simply to do what was already done in PHP, without running exec on PHP of course.
I suspect I'm doing something wrong with strings somewhere.