2013-12-13 36 views
2

我有這個C++在Visual Studio中開發計劃,其中應打印出給定的字符串的SHA1和MD5哈希值:SHA1功能給人怪異的輸出

#include "stdafx.h" 
#include <iostream> 
#include <ctime> 
#include "windows.h" 
#include "conio.h" 
#include "wincrypt.h" 

char Buf [256]; 
DWORD BufSize; 

LPSTR CreateHash(LPSTR tohash, ALG_ID alg) 
{ 
    HCRYPTPROV hProv; 
    HCRYPTHASH hash; 

    if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 
     CRYPT_VERIFYCONTEXT)) 
    { 
     if (CryptCreateHash(hProv, alg, 0, 0, &hash)) 
     { 
      if (CryptHashData(hash, (BYTE *)&tohash, sizeof(tohash), 0)) 
      { 
       ZeroMemory(&Buf, sizeof(Buf)); 
       BufSize = sizeof(Buf); 

       if (!CryptGetHashParam(hash, HP_HASHVAL, 
        (BYTE *) &Buf, &BufSize, 0)) 
        printf("Call to CryptGetHashParam failed. Error: %d\n", 
        GetLastError()); 

      } else printf("Call to CryptHashData failed. Error: %d\n", 
       GetLastError()); 

      if (!CryptDestroyHash(hash)) 
       printf("Call to CryptDestroyHash failed. Error: %d\n", 
       GetLastError()); 

     } else printf("Call to CryptCreateHash failed. Error: %d\n", 
      GetLastError()); 

     if (!CryptReleaseContext(hProv, 0)) 
      printf("Call to CryptReleaseContext failed. Error: %d\n", 
      GetLastError()); 

    } else printf("Call to CryptAcquireContext failed. Error: %d\n", 
     GetLastError()); 

    return Buf; 
} 

using namespace std; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    cout << "SHA hash: " << CreateHash("Visual C++", CALG_SHA)<<endl; 
    cout << "MD5 hash: " << CreateHash("Visual C++", CALG_MD5)<<endl; 

    system("pause"); 
} 

它編譯,但是當我運行它,它顯示了怪異輸出。

輸出應該

SHA hash: 0e4abc18f9fb9d8d6d39f047dc20fbebd4a975bd 
MD5 hash: f3be2f04531a477a4bb755f9f42c6f2e 

但它打印

SHA hash: ü©á*ÀªvÍŒe²5Ê¥Å?•Â 
MD5 hash: òù%•þîOú°b>«’ 

爲什麼?

我該如何解決這個問題?

+4

它的原始輸出爲字節而不是十六進制。 – towr

+1

除非需要支持XP,否則應該使用[下一代加密](http://msdn.microsoft.com/en-us/library/windows/desktop/aa376210(v = vs.85).aspx) API更容易和更安全地使用,並暴露更多的算法。 – Mgetz

+0

@towr如何將原始輸出轉換爲十六進制輸出? – user3099950

回答

1

加密函數將以原始字節存儲輸出。您期待您的輸出採用Base64或十六進制編碼。爲了達到目的,你需要調用將原始二進制數據轉換爲你想要的編碼的字符串的函數。你可以看到如何做到這一點的示例here

(例如複製)

CString BinaryToBase64(__in const BYTE * pbBinary, __in DWORD cbBinary) 
{ 
    // Check input pointer 
    ATLASSERT(pbBinary != NULL); 
    if (pbBinary == NULL) 
     AtlThrow(E_POINTER); 

    // Check input size 
    ATLASSERT(cbBinary != 0); 
    if (cbBinary == 0) 
     AtlThrow(E_INVALIDARG); 

    // Request size of Base64 string 
    DWORD cchBase64; 
    if (!CryptBinaryToString(pbBinary, cbBinary, CRYPT_STRING_BASE64, NULL, &cchBase64)) 
    { 
     AtlThrowLastWin32(); 
    } 

    // Allocate a string with required size 
    CString strBase64; 
    LPTSTR pszBase64 = strBase64.GetBuffer(cchBase64); 
    ATLASSERT(pszBase64 != NULL); 

    // Convert binary data to Base64 
    if (!CryptBinaryToString(pbBinary, cbBinary, CRYPT_STRING_BASE64, pszBase64, &cchBase64)) 
    { 
     AtlThrowLastWin32(); 
    } 

    // Release CString buffer 
    strBase64.ReleaseBuffer(); 

    // Return the converted string 
    return strBase64; 
} 

你要調用的函數爲CryptBinaryToString

cout << hex << (unsigned int) result[i]; 

如果必須直接打印從函數的返回值,然後創建一個包含結果緩衝區結構和重載operator<<打印緩衝區:

+0

OP在哪裏提到Base64? –

+0

我沒有提到Base64,我提到了SHA1和MD5。無論如何,將原始二進制數據轉換爲SHA1/MD5 string_的函數是什麼? – user3099950

+0

@ThomasMatthews我正在調整,因爲它看起來他的字符串實際上是十六進制的。 –

0

我使用字節結果打印出來字節結構。

+0

問題是,我想有十六進制格式的字符串,而不必在打印時轉換它,因爲我打算使用該字符串將其值與其他字符串進行比較。那可能嗎? – user3099950

+0

他的散列將是一個'bytes'數組,它們是'unsigned char's。 –

+0

@ZacHowland:如果不投射,如何告訴'cout'來區分C風格的字符串(char *)和字節?我通過搜索「StackOverflow cout hex」找到了很多我的方法的例子。 –