2013-12-13 35 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”找到了很多我的方法的例子。 –