2016-12-04 16 views
1

我有一個程序從文件生成散列鍵。 例如程序的結果是"hash of file c:\Users\Jax\Desktop\files\file.txt is: 4db5a10d2ea73e3f76"hashResult變量沒有存儲正確的值

而且我有了這個file.txt的期望的散列變量:

char hashExpected = "4db5a10d2ea73e3f76"; 

而且在我驗證碼的specifc一部分,如果該方案的結果散列等於哈希存儲在hashExpected變量中。我有這樣的下面。我有hashResult變量存儲結果散列,然後我可以比較。但它不能正常工作,因爲即使它相等,它總是顯示Hash is different。看來hashResult變量沒有存儲正確的值。

 for (i = 0; i < cbHash; i++) 
     { 
      printf("%c%c", 
        rgbDigits[rgbHash[i] >> 4], 
        rgbDigits[rgbHash[i] & 0xf]); 
      hashResult[i] = rgbDigits[rgbHash[i] >> 4]; 
      hashResult[i] += rgbDigits[rgbHash[i] & 0xf]; 
     } 
     if (verify(hashResult, hashExpected)) 
     { 
      printf("Hash is the same\n"); 
     } 
     else 
     { 
      printf("Hash is different\n"); 
     } 

全部程序:

#include <stdio.h> 
#include <windows.h> 
#include <Wincrypt.h> 
#include <stdbool.h> 
#define BUFSIZE 1024 
#define MD5LEN 16 

bool verify(char array1[], char array2[]) 
{ 
    int i; 
    for (i = 0; array1[i] && array2[i]; ++i) 
    { 
     if (array1[i] != array2[i]) 
     { 
      return false; 
     } 
    } 
    return true; 
} 
DWORD main() 
{ 
    DWORD dwStatus = 0; 
    BOOL bResult = FALSE; 
    HCRYPTPROV hProv = 0; 
    HCRYPTHASH hHash = 0; 
    HANDLE hFile = NULL; 
    BYTE rgbFile[BUFSIZE]; 
    DWORD cbRead = 0; 
    BYTE rgbHash[MD5LEN]; 
    DWORD cbHash = 0; 
    CHAR rgbDigits[] = "abcdef"; 
    PCSTR filename = "c:\\Users\\Jax\\Desktop\\files\\file.txt"; 
    char hashActual[] = "4db5a10d2ea73e3f76"; 
    char hashExpected[] = "4db5a10d2ea73e3f76"; 
    char hashWrong[] = "0a0a0a0a0a0a0a"; 
    char hashResult[] = ""; 
    hFile = CreateFile(filename, 
         GENERIC_READ, 
         FILE_SHARE_READ, 
         NULL, 
         OPEN_EXISTING, 
         FILE_FLAG_SEQUENTIAL_SCAN, 
         NULL); 


    if (INVALID_HANDLE_VALUE == hFile) 
    { 
     dwStatus = GetLastError(); 
     printf("Error opening file %s\nError: %d\n", filename, 
       dwStatus); 
     return dwStatus; 
    } 


    // Get handle to the crypto provider 
    if (!CryptAcquireContext(&hProv, 
          NULL, 
          NULL, 
          PROV_RSA_FULL, 
          CRYPT_VERIFYCONTEXT)) 
    { 
     dwStatus = GetLastError(); 
     printf("CryptAcquireContext failed: %d\n", dwStatus); 
     CloseHandle(hFile); 
     return dwStatus; 
    } 


    if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) 
    { 
     dwStatus = GetLastError(); 
     printf("CryptAcquireContext failed: %d\n", dwStatus); 
     CloseHandle(hFile); 
     CryptReleaseContext(hProv, 0); 
     return dwStatus; 
    } 


    while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, 
           &cbRead, NULL)) 
    { 
     if (0 == cbRead) 
     { 
      break; 
     } 


     if (!CryptHashData(hHash, rgbFile, cbRead, 0)) 
     { 
      dwStatus = GetLastError(); 
      printf("CryptHashData failed: %d\n", dwStatus); 
      CryptReleaseContext(hProv, 0); 
      CryptDestroyHash(hHash); 
      CloseHandle(hFile); 
      return dwStatus; 
     } 
    } 


    if (!bResult) 
    { 
     dwStatus = GetLastError(); 
     printf("ReadFile failed: %d\n", dwStatus); 
     CryptReleaseContext(hProv, 0); 
     CryptDestroyHash(hHash); 
     CloseHandle(hFile); 
     return dwStatus; 
    } 


    cbHash = MD5LEN; 


    if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) 
    { 
     DWORD i; 

     printf("MD5 hash of file %s is: ", filename); 
     for (i = 0; i < cbHash; i++) 
     { 
      printf("%c%c", 
        rgbDigits[rgbHash[i] >> 4], 
        rgbDigits[rgbHash[i] & 0xf]); 
      hashResult[i] = rgbDigits[rgbHash[i] >> 4]; 
      hashResult[i] += rgbDigits[rgbHash[i] & 0xf]; 


     } 
     if (verify(hashResult, hashExpected)) 
     { 
      printf("Hash is the same\n"); 
     } 
     else 
     { 
      printf("Hash is different\n"); 
     } 
    } 
    else 
    { 
     dwStatus = GetLastError(); 
     printf("CryptGetHashParam failed: %d\n", dwStatus); 
    } 


    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    CloseHandle(hFile); 


    return dwStatus; 
} 
+1

緩衝區溢出:你'hashResult'陣列只有一個元素。你可以用'hashResult [i] = ...'來訪問它,這是超出界限的。 – melpomene

回答

0
char hashExpected[] = "4db5a10d2ea73e3f76"; 

以上MD5值是錯誤的。 MD5值是16個字節長。但這只是字節。我們無法在屏幕上打印字節,因此經常將字節轉換爲十六進制值。例如,如果我們有unsinged char bytes[3] = {0x01,0x01,0xFF},我們將字節轉換爲十六進制字符串,它將變成"0102FF"

請注意,字符串表示是兩次加上一個nul終結符。 MD5哈希的例子是:

"C4CA4238A0B923820DCC509A6F75849B" 

的字符串緩衝區大小應該是33(16×2 + 1)

爲了找到正確的hashExpected,搜索「在線MD5計算器」。您可以使用像http://onlinemd5.com/這樣的網站來計算文件的MD5。

或使用內容爲1的文件。 MD5("1")"C4CA4238A0B923820DCC509A6F75849B",使用它作爲預期的散列值。

char hashResult[] = ""; 

上面一行是一個編程錯誤,如@melpomene

hashResult[i] = rgbDigits[rgbHash[i] >> 4]; 
hashResult[i] += rgbDigits[rgbHash[i] & 0xf]; 

上面的代碼是錯誤的評論中提到,你想這個代替:

char hashResult[MD5LEN * 2 + 1] = ""; 
... 
hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4]; 
hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf]; 

也有一個問題功能verify,因爲它比較字節表示中錯誤的MD5與字符串表示中錯誤的MD5。

您可以使用strcmp_stricmp來比較字符串表示中的MD5值。或者使用memcmp(data1, data2, 16)直接比較字節。

完整的示例:

#define BUFSIZE 1024 
#define MD5LEN 16 

int main() 
{ 
    DWORD dwStatus = 0; 
    HCRYPTPROV hProv = 0; 
    HCRYPTHASH hHash = 0; 
    HANDLE hFile = NULL; 
    BYTE rgbFile[BUFSIZE]; 
    DWORD cbRead = 0; 
    BYTE rgbHash[MD5LEN]; 
    DWORD cbHash = 0; 
    CHAR rgbDigits[] = "abcdef"; 
    PCSTR filename = "c:\\Users\\Jax\\Desktop\\files\\file.txt"; 

    //assuming content of file.txt is '1' 
    char hashExpected[] = "C4CA4238A0B923820DCC509A6F75849B"; 

    char hashResult[MD5LEN * 2 + 1] = ""; 
    hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 
     NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 

    if(INVALID_HANDLE_VALUE == hFile) 
    { 
     dwStatus = GetLastError(); 
     printf("Error opening file %s\nError: %d\n", filename, dwStatus); 
     return (int)dwStatus; 
    } 

    // Get handle to the crypto provider 
    if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 
    { 
     dwStatus = GetLastError(); 
     printf("CryptAcquireContext failed: %d\n", dwStatus); 
     CloseHandle(hFile); 
     return (int)dwStatus; 
    } 

    if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) 
    { 
     dwStatus = GetLastError(); 
     printf("CryptAcquireContext failed: %d\n", dwStatus); 
     CloseHandle(hFile); 
     CryptReleaseContext(hProv, 0); 
     return (int)dwStatus; 
    } 

    while(ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL)) 
    { 
     if(0 == cbRead) 
      break; 

     if(!CryptHashData(hHash, rgbFile, cbRead, 0)) 
     { 
      dwStatus = GetLastError(); 
      printf("CryptHashData failed: %d\n", dwStatus); 
      CryptReleaseContext(hProv, 0); 
      CryptDestroyHash(hHash); 
      CloseHandle(hFile); 
      return (int)dwStatus; 
     } 
    } 

    cbHash = MD5LEN; 

    if(CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) 
    { 
     DWORD i; 

     printf("MD5 expected, versus MD5 of file %s is:\n", filename); 
     printf("%s\n", hashExpected); 
     for(i = 0; i < cbHash; i++) 
     { 
      printf("%c%c", 
       rgbDigits[rgbHash[i] >> 4], 
       rgbDigits[rgbHash[i] & 0xf]); 
      hashResult[i * 2] = rgbDigits[rgbHash[i] >> 4]; 
      hashResult[i * 2 + 1] = rgbDigits[rgbHash[i] & 0xf]; 
     } 
     printf("\n"); 

     if(_strcmpi(hashResult, hashExpected) == 0) 
      printf("Hash is the same\n"); 
     else 
      printf("Hash is different\n"); 
    } 
    else 
    { 
     dwStatus = GetLastError(); 
     printf("CryptGetHashParam failed: %d\n", dwStatus); 
    } 

    CryptDestroyHash(hHash); 
    CryptReleaseContext(hProv, 0); 
    CloseHandle(hFile); 

    return (int)dwStatus; 
} 
+0

非常感謝您的詳細解釋。現在我明白了這個問題。現在我試着實驗你的解決方案,但它顯示一個奇怪的錯誤「錯誤:':: main'必須返回'int'」。你知道爲什麼可以嗎? – Jax

+0

謝謝您的解決方案!再次感謝您的詳細解釋。 – Jax