MD5 Crypto API возвращает неверный хэш для определенных открытых текстов

Я пытаюсь использовать криптографические API Microsoft для вычисления хэша MD5, но получаю неверные хэши:

#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;
}

Код выполняется нормально, сообщение об ошибке не выводится, но возвращаемое хеш-значение неверно для некоторых открытых текстов:

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

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

Последнее правильно, но первое должно быть 098f6bcd4621d373cade4e832627b4f6.

Что я делаю неправильно?


person Polynomial    schedule 02.01.2012    source источник
comment
это работа для сайта проверки кода.   -  person bmargulies    schedule 02.01.2012
comment
@bmargulies: Нет, проверка кода не предназначена для проверки кода с ошибками. Это действительно принадлежит здесь.   -  person Niklas B.    schedule 02.01.2012
comment
Согласно часто задаваемым вопросам по проверке кода, они проверяют код, который работает, но, возможно, не оптимален. Они также заявляют, что проверка кода не предназначена для устранения неполадок. Этот код не работает и требует устранения неполадок.   -  person Polynomial    schedule 02.01.2012
comment
На самом деле оба хэша неверны (хотя и не полностью), поэтому я подозреваю, что преобразование в шестнадцатеричное ошибочно.   -  person Niklas B.    schedule 02.01.2012


Ответы (2)


char *hex = "01234567879abcdef";

У вас ошибка в этой строке.

Следует читать:

char *hex = "0123456789abcdef";
person jv42    schedule 02.01.2012
comment
*facepalm*... Спасибо, что заметили это! - person Polynomial; 02.01.2012

strHash[i*2]     = hex[hash[i] >> 4];
strHash[(i*2)+1] = hex[hash[i] & 0xF];

strHash указывает на строковый литерал. строковые литералы не поддаются изменению. Изменение строкового литерала является неопределенным поведением.

person ouah    schedule 02.01.2012
comment
Я исправил код, чтобы вместо этого использовать malloc(), но все еще имею ту же проблему. - person Polynomial; 02.01.2012
comment
+1: не проблема (как оказалось), но, тем не менее, отличный момент. - person ruakh; 02.01.2012
comment
@ Дэйв, проблема в том, что он возвращает strHash в конце функции, поэтому он не может этого сделать. - person ouah; 02.01.2012