5

使用 CryptoAPI 创建 HMAC 步骤,在此处找到:http: //msdn.microsoft.com/en-us/library/Aa379863

  • 计算 HMAC

    1. 通过调用 CryptAcquireContext 获取指向 Microsoft 加密服务提供程序 (CSP) 的指针。
    2. 通过调用 CryptCreateHash 创建 HMAChash 对象的句柄。在 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 与键组合外部字符串。异或运算的结果被哈希,然后内部哈希的结果(在上一步中完成)被哈希。然后完成外部散列并在 pbData 参数中返回,长度在 dwDataLen 参数中返回。

我不能,因为我的生活让这个工作。我按顺序完成了所有步骤,但仍然无法运行我的程序。运行时出错:

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

任何人都可以帮忙吗?

#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;
}
4

1 回答 1

2

您可能 (? 1 ) 需要指定要使用的哈希算法。

#define CALG_HMAC CALG_SHA1 // or CALG_MD5 etc

编辑

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

  • 你为什么从SHA1改变哈希算法

  • 为什么不再在 ErrorExit 上退出(仅此一项就可以防止崩溃而不是正确的错误消息)

  • 您使用CryptImportKey而不是CryptDeriveKey- MSDN 上的示例中甚至不存在这样的东西。CryptImportKey 是调用失败并显示 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

它在运行时确实崩溃了(没有参数),但这可能是葡萄酒不兼容(或者我没有阅读源代码来查看它的作用:))

于 2011-09-25T19:25:57.600 回答