alucard
alucard

Reputation: 23

Strange behavior of Win32 MD5 hasher

I use this function to generate a hash of a string

std::string MD5(string input)
{
    BYTE BytesHash[33];//!
    DWORD dwHashLen;
    string final;   
    HCRYPTPROV CryptProv;
    HCRYPTHASH CryptHash;
    if (CryptAcquireContext(&CryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) {
        if (CryptCreateHash(CryptProv, CALG_MD5, 0, 0, &CryptHash))     {
            if (CryptHashData(CryptHash, (BYTE*)input.c_str(), input.length(), 0))          {
                if (CryptGetHashParam(CryptHash, HP_HASHVAL, BytesHash, &dwHashLen, 0))             {
                    final.clear();
                    string hexcharset = "0123456789ABCDEF";
                    for (int j = 0; j < 16; j++) {
                        final += hexcharset.substr(((BytesHash[j] >> 4) & 0xF), 1);
                        final += hexcharset.substr(((BytesHash[j]) & 0x0F), 1);
                    }
                }
            }
        }
    }   CryptDestroyHash(CryptHash);
    CryptReleaseContext(CryptProv, 0);
    return final;

}

But I have a problem. Some users of the compiled binary can not generate md5. However, I insert between some lines:

cout << "randomstring:gfdgfdgfdgfdg" << endl;

And now everything is working for those users, but does not work for some others. What the hell?

Upvotes: 0

Views: 433

Answers (1)

Yirkha
Yirkha

Reputation: 13868

The 4th parameter of CryptGetHashParam, pdwDataLen, has two functions. Upon entry, it specifies the length of the available buffer. Upon exit, it contains the length of the really used data. This is fairly common concept in Windows API.

Because you do not initialize dwHashLen with any value, whatever is currently on the stack is passed to the function. If it's less than the size of the hash value, it does not work and the function returns error. If it happens to be bigger, it works. Doing some other unrelated operation can change the stack in random ways, therefore make it work sometimes.

The solution is therefore to initialize the size like this:

DWORD dwHashLen = sizeof(BytesHash);

You might want to check GetLastError() next time something like this happens, it would tell you a hint about what went wrong (ERROR_MORE_DATA).

Upvotes: 5

Related Questions