2012-11-06 11 views
5

Moja aplikacja C++ musi obliczyć wartość mieszania MD5, obecnie jest to zrobione przez OpenSSL i chcę przenieść ją do wykorzystania WinAPI - aby uniknąć zależności w zewnętrznych bibliotekach.
Napisałem ten kod:Oblicz wartość mieszania MD5 przez C++ WinAPI

HCRYPTPROV hCryptProv = NULL; 
HCRYPTHASH hHash = NULL; 
HCRYPTHASH hHexHash = NULL; 
HASH HA1; 
HASHHEX HA1HEX; 
DWORD data = HASHLEN; 

// Get a handle to a cryptography provider context. 
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) 
{ 
    goto err; 
} 

// Acquire a hash object handle. 
if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash)) 
{ 
    goto err; 
} 

CryptHashData(hHash, (const BYTE *)str, strlen(str), 0); 

teraz, dziwne jest to, że somtimes to działa dobrze, ale w innych czasach powrót CryptAcquireContext z błędu NTE_BAD_KEYSET że zgodnie MSDN:

Kluczem pojemnik nie może być otwartym. Częstą przyczyną tego błędu jest to, że kontener klucza nie istnieje. Aby utworzyć kontener klucza, wywołaj CryptAcquireContext za pomocą flagi CRYPT_NEWKEYSET. Ten kod błędu może również wskazywać, że dostęp do istniejącego kontenera kluczy jest zabroniony. Prawa dostępu do kontenera mogą być nadane przez twórcę zestawu kluczy za pomocą CryptSetProvParam.

Blockquote

Teraz moje pytania to:

  1. jeśli zadzwonię do CryptSetProvParam, co exceactly to robi? czy to normalne, że prosta aplikacja zmieni ustawienia systemu operacyjnego?
  2. Czy istnieje mniej trudny sposób wykonywania obliczeń MD5 w oknach C++?

Zatwierdzam, jeśli ktoś będzie mógł mi doradzić, co robić.
Dzięki

+1

Implementacja dedykowana domenie publicznej [można znaleźć tutaj] (http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5). –

+0

dziękuję, ale na razie wolę go nie wdrażać. – RRR

+3

Nie wdrożysz tego samodzielnie. Po prostu upuść md5.c i md5.h do swojego projektu i wywołaj funkcje. –

Odpowiedz

6

Tak, znalazłem przykład, że robi to, co chcesz w http://msdn.microsoft.com/en-us/library/aa382380%28VS.85%29.aspx

Patrząc na ich kodu, różnica widzę, to ta linia:

Ich: CryptAcquireContext (& hCryptProv, NULL NULL PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)

wyrazami: CryptAcquireContext (& hCryptProv NULL NULL, PROV_RSA _FULL, 0)

Tak, czytania na tej flagi, znajdę te informacje:

CRYPT_VERIFYCONTEXT: Ta opcja jest przeznaczona dla aplikacji, które korzystają z klawiszy efemeryczne lub aplikacji, które nie wymagają dostępu do utrzymywały klucze prywatne, takie jak aplikacje, które wykonują jedynie haszowanie, szyfrowanie i weryfikację podpisu cyfrowego. Tylko aplikacje, które tworzą sygnatury lub odszyfrowują wiadomości, potrzebują dostępu do klucza prywatnego. W większości przypadków ta flaga powinna być ustawiona.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa379886%28v=vs.85%29.aspx

Tak, wygląda na to, próbują uzyskać dostęp do informacji nie trzeba, a wniosek zostanie odrzucony. Najlepszą opcją jest poinformowanie Windows, że nie potrzebujesz tych informacji, włączając tę ​​flagę.

3

Lubię używać PROV_RSA_AES i CRYPT_VERIFYCONTEXT, ponieważ większość skrótów jest obsługiwana.

Oto przykład roboczych:

#include <Wincrypt.h> 

enum HashType 
{ 
    HashSha1, HashMd5, HashSha256 
}; 

std::string GetHashText(const void * data, const size_t data_size, HashType hashType) 
{ 
    HCRYPTPROV hProv = NULL; 

    if (! CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { 
    return ""; 
    } 

    BOOL hash_ok = FALSE; 
    HCRYPTPROV hHash = NULL; 
    switch (hashType) { 
    case HashSha1 : hash_ok = CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash); break; 
    case HashMd5 : hash_ok = CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash); break; 
    case HashSha256 : hash_ok = CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash); break; 
    } 

    if (! hash_ok) { 
    CryptReleaseContext(hProv, 0); 
    return ""; 
    } 

    if (! CryptHashData(hHash, static_cast<const BYTE *>(data), data_size, 0)) { 
    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    return ""; 
    } 

    DWORD cbHashSize = 0, dwCount = sizeof(DWORD); 
    if(! CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize, &dwCount, 0)) { 
    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    return ""; 
    } 

    std::vector<BYTE> buffer(cbHashSize); 
    if (! CryptGetHashParam(hHash, HP_HASHVAL, reinterpret_cast<BYTE*>(&buffer[0]), &cbHashSize, 0)) { 
    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    return ""; 
    } 

    std::ostringstream oss; 

    for (std::vector<BYTE>::const_iterator iter = buffer.begin(); iter != buffer.end(); ++iter) { 
    oss.fill('0'); 
    oss.width(2); 
    oss << std::hex << static_cast<const int>(*iter); 
    } 

    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    return oss.str(); 
} 
1

mam to link

ale zrobiłem kilka zmian w celu uruchomienia tej funkcji po mojej stronie, mam nadzieję, może pomóc

char* HashMD5(char* data, DWORD *result) 
{ 
    DWORD dwStatus = 0; 
    DWORD cbHash = 16; 
    int i = 0; 
    HCRYPTPROV cryptProv; 
    HCRYPTHASH cryptHash; 
    BYTE hash[16]; 
    char *hex = "abcdef"; 
    char *strHash; 
    strHash = (char*)malloc(500); 
    memset(strHash, '\0', 500); 
    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; 
}