MD5 Crypto API returns incorrect hash for certain

2019-06-14 12:09发布

I'm attempting to use the Microsoft crypto APIs to compute an MD5 hash, but I'm getting incorrect hashes:

#include <windows.h>
#include <stdio.h>
#include <wincrypt.h>

char* HashMD5(char* data, DWORD *result)
{
    DWORD dwStatus = 0;
    DWORD cbHash = 16;
    int i = 0;
    HCRYPTPROV cryptProv;
    HCRYPTHASH cryptHash;
    BYTE hash[16];
    char *hex = "01234567879abcdef";
    char *strHash = "00000000000000000000000000000000";
    if(!CryptAcquireContext(&cryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    {
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %d\n", dwStatus);
        *result = dwStatus;
        return NULL;
    }
    if(!CryptCreateHash(cryptProv, CALG_MD5, 0, 0, &cryptHash))
    {
        dwStatus = GetLastError();
        printf("CryptCreateHash failed: %d\n", dwStatus);
        CryptReleaseContext(cryptProv, 0);
        *result = dwStatus;
        return NULL;
    }
    if(!CryptHashData(cryptHash, (BYTE*)data, strlen(data), 0))
    {
        dwStatus = GetLastError();
        printf("CryptHashData failed: %d\n", dwStatus);
        CryptReleaseContext(cryptProv, 0);
        CryptDestroyHash(cryptHash);
        *result = dwStatus;
        return NULL;
    }
    if(!CryptGetHashParam(cryptHash, HP_HASHVAL, hash, &cbHash, 0))
    {
        dwStatus = GetLastError();
        printf("CryptGetHashParam failed: %d\n", dwStatus);
        CryptReleaseContext(cryptProv, 0);
        CryptDestroyHash(cryptHash);
        *result = dwStatus;
        return NULL;
    }
    for(i = 0; i < cbHash; i++)
    {
        strHash[i*2]     = hex[hash[i] >> 4];
        strHash[(i*2)+1] = hex[hash[i] & 0xF];
    }
    CryptReleaseContext(cryptProv, 0);
    CryptDestroyHash(cryptHash);
    return strHash;
}

int main(int argc, char **argv)
{
    DWORD result = 0;
    char* hash;
    if(argc != 2)
    {
        printf("Usage: crypto.exe <word>\n");
        return 0;
    }
    hash = HashMD5(argv[1], &result);
    if(result == 0)
    {
        printf("Hash of '%s' is: %s\n", argv[1], hash);
    }
    else
    {
        printf("Failed! Result: %d\n", result);
    }
    return result;
}

The code executes fine, no error message is printed, but the returned hash value is incorrect for certain plaintexts:

$ ./crypto.exe test
Hash of 'test' is: 078e6abc4621c373b9cd4d832627a4e6

$ ./crypto.exe StackOverflow
Hash of 'StackOverflow' is: 84c7cb17766b446e5d4084d8ebd87e82

The latter is correct, but the former should be 098f6bcd4621d373cade4e832627b4f6.

What am I doing wrong?

2条回答
仙女界的扛把子
2楼-- · 2019-06-14 12:46
char *hex = "01234567879abcdef";

You have an error in that line.

It should read:

char *hex = "0123456789abcdef";
查看更多
ら.Afraid
3楼-- · 2019-06-14 12:55
strHash[i*2]     = hex[hash[i] >> 4];
strHash[(i*2)+1] = hex[hash[i] & 0xF];

strHash points to a string literal. string literal are non-modifiable. Modifying a string literal is undefined behavior.

查看更多
登录 后发表回答