MSDN HMAC-SHA1示例无法工作

5
使用CryptoAPI创建HMAC的步骤如下:http://msdn.microsoft.com/en-us/library/Aa379863
  • 计算HMAC

    1. 通过调用CryptAcquireContext获取指向Microsoft Cryptographic Service Provider (CSP)的指针。
    2. 通过调用CryptCreateHash创建一个HMAC哈希对象句柄。在Algid参数中传递CALG_HMAC。在hKey参数中传递对称密钥的句柄。该对称密钥用于计算HMAC。
    3. 通过调用CryptSetHashParam指定要使用的哈希类型,并将dwParam参数设置为HP_HMAC_INFO的值。pbData参数必须指向已初始化的HMAC_INFO结构。
    4. 调用CryptHashData开始计算数据的HMAC。第一次调用CryptHashData会使用XOR运算符将密钥值与内部字符串和数据组合。 XOR操作的结果进行哈希,然后哈希目标数据以计算HMAC(由传递给CryptHashData调用的pbData参数指向)。如果需要,可以随后调用CryptHashData以完成目标数据的哈希。
    5. 调用CryptGetHashParam并将dwParam参数设置为HP_HASHVAL。此调用导致内部哈希完成并使用XOR与密钥组合。 XOR操作的结果进行哈希,然后哈希内部哈希的结果(在上一步中完成)。然后完成外部哈希,并将结果返回到pbData参数中,长度在dwDataLen参数中。

我无论如何都无法使其正常工作。我已按顺序执行了所有步骤,但仍无法运行程序。运行时出现错误:

Error in CryptImportKey 0x8009007
Error in CryptCreatHash 0x8009003
Error in CryptSetHashParam 0x00000057
Error in CryptHashData 0x00000057
Error in CryptGetHashParam 0x00000057

Can anyone help?

#include <iostream>
#include <windows.h>
#include <wincrypt.h>
using namespace std;

#define CALG_HMAC CALG_SHA1

int main()
{
//--------------------------------------------------------------------
// Declare variables.
HCRYPTPROV  hProv       = NULL;
HCRYPTHASH  hHash       = NULL;
HCRYPTKEY   hKey        = NULL;
BYTE DesKeyBlob[] = { 0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64 };
HCRYPTHASH  hHmacHash   = NULL;
PBYTE       pbHash      = NULL;
DWORD       dwDataLen   = 20;
BYTE        Data[]     = {0x6D,0x65,0x73,0x73,0x61,0x67,0x65};
HMAC_INFO   HmacInfo;

//--------------------------------------------------------------------
// Zero the HMAC_INFO structure
ZeroMemory(&HmacInfo, sizeof(HmacInfo));
HmacInfo.HashAlgid = CALG_HMAC;
HmacInfo.pbInnerString = (BYTE*)0x36;
HmacInfo.cbInnerString = 0;
HmacInfo.pbOuterString = (BYTE*)0x5C;
HmacInfo.cbOuterString = 0;

// Step 1
if (!CryptAcquireContext(
    &hProv,                   // handle of the CSP
    NULL,                     // key container name
    NULL,                     // CSP name
    PROV_RSA_FULL,            // provider type
    CRYPT_VERIFYCONTEXT))     // no key access is requested
{
   printf(" Error in AcquireContext 0x%08x \n",
          GetLastError());
}

//--------------------------------------------------------------------
//Step 2
//in step two, we need the hash key used to be imported?
//imports the key used...  as hKey1
if(!CryptImportKey(
       hProv,
       DesKeyBlob,
       sizeof(DesKeyBlob),
       0,
       CRYPT_EXPORTABLE,
       &hKey ))
{
       printf("Error in !CryptImportKey 0x%08x \n",
          GetLastError());
}

if (!CryptCreateHash(
    hProv,      // handle of the CSP
    CALG_HMAC,  // hash algorithm to use
    hKey,       // hash key this shoudl point to a key used to compute the HMAC?
    0,          // reserved
    &hHmacHash  // address of hash object handle
)){
   printf("Error in CryptCreateHash 0x%08x \n",
          GetLastError());
}
// Step 3

if (!CryptSetHashParam(
    hHmacHash,//hProv,//hHash,//hHmacHash,                // handle of the HMAC hash object
    HP_HMAC_INFO,             // setting an HMAC_INFO object
    (BYTE*)&HmacInfo,         // the HMAC_INFO object
    0))                       // reserved
{
   printf("Error in CryptSetHashParam 0x%08x \n", 
          GetLastError());
}

//Step 4

if (!CryptHashData(
    hHmacHash,                // handle of the HMAC hash object
    Data,                    // message to hash
    sizeof(Data),            // number of bytes of data to add
    0))                       // flags
{
   printf("Error in CryptHashData 0x%08x \n", 
          GetLastError());
}
//Step 5

if (!CryptGetHashParam(
    hHmacHash,                 // handle of the HMAC hash object
    HP_HASHVAL,                // query on the hash value
    pbHash,                    // pointer to the HMAC hash value
    &dwDataLen,                // length, in bytes, of the hash
    0))
{
   printf("Error in CryptGetHashParam 0x%08x \n", GetLastError());
}

// Print the hash to the console.

printf("The hash is:  ");
for(DWORD i = 0 ; i < dwDataLen ; i++) 
{
   printf("%2.2x ",pbHash[i]);
}
printf("\n");

int a;

std::cin >> a;

    return 0;
}

2
编译时出现了哪些错误? - Andy Finkenstadt
抱歉,我的意思是运行而不是编译。当我运行时遇到的错误是: CryptImportKey 错误 0x8009007 CryptCreatHash 错误 0x8009003 CryptSetHashParam 错误 0x00000057 CryptHashData 错误 0x00000057 CryptGetHashParam 错误 0x00000057 - user954753
这绝不是 MSDN 上的示例应用程序。它已经多次更改:请参阅 http://msdn.microsoft.com/en-us/library/aa382379(v=VS.85).aspx。 - sehe
这并没有返回真实的值,证据在于:http://buchananweb.co.uk/security01.aspx :-( - user954753
1个回答

2

你可能需要指定你想要使用的哈希算法。

#define CALG_HMAC CALG_SHA1 // or CALG_MD5 etc

编辑

  • 为什么你要将dwDataLen = 20初始化为20(而不是0)?

  • 为什么你改变了哈希算法,从SHA1转变成了其他的算法?

  • 为什么你不再在ErrorExit上退出程序(只有正确的错误信息才能避免程序崩溃)?

  • 你使用的是CryptImportKey而不是CryptDeriveKey--而MSDN上的示例中并没有这个函数。这个调用失败的原因很可能是0x80090005(NTE_BAD_DATA)。密钥不被你的CSP支持!

  • 要使它工作,你需要获得密钥访问权,所以至少需要将CRYPT_VERIFY_CONTEXT更改为其他内容(我不知道是什么)。我尝试过使用

.

if (!CryptAcquireContext(
            &hProv,                   
            NULL,                     
            MS_STRONG_PROV,           // allow 2048 bit keys, in case you need it
            PROV_RSA_FULL,            
            CRYPT_MACHINE_KEYSET))    // just a guess

现在我的程序出现了0x80090016: Keyset does not exist的结果。这可能是因为我没有该密钥集,或者因为我在Wine下的Linux上运行。

希望这可以帮到你。


1 使用以下编译的Linux:

i586-mingw32msvc-g++ -m32 -O2 -g test.cpp -o test.exe

它在运行时崩溃了(没有参数),但这可能是因为wine不兼容(或者我没有阅读源代码以查看其功能:)

新增:#define CALG_HMAC CALG_SHA1现在我遇到了错误:CryptImportKey 0x80090007 和 CryptSetHashParam 0x8009000A。你使用了我发布的代码吗? - user954753
@user954753:还有什么问题吗?不过,你后来发布了运行时错误 - 我得到了 !CryptImportKey 0x80090005 错误和 CryptSetHashParam 0x80090020 错误 - 看起来很相似。我担心还有其他问题(但是我回答了这个问题,因为你提到它不能编译,在没有那个定义的情况下,对我来说也无法编译)。 - sehe
我深入挖掘并找到了一些线索,可能会对你有所帮助。尤其是你尝试使用CryptImportKey可能比你想象的更为严重(就获取提供程序上下文而言)。 - sehe
为什么你把 dwDataLen 的初始化设置为20(而不是0)?-> 我希望输出的长度为20字节。 你为什么要将哈希算法从 SHA1 改变-> 我只是试图遵循这5个步骤。我按照步骤中告诉我的做了一切。 - user954753
@user954753:答案是:问题_不在_于执行HMAC的步骤,而在于执行CryptImportKey的步骤。需要阅读不同的教程。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接