使用带有Microsoft CAPI的SHA1

时间:2010-05-28 09:49:38

标签: c cryptoapi

我有一个SHA1哈希,我需要签名。 CryptSignHash()方法需要一个HCRYPTHASH句柄进行签名。我创建它,因为我已经有了实际的哈希值,然后设置它:

CryptCreateHash(cryptoProvider, CALG_SHA1, 0, 0, &hash);
CryptSetHashParam(hash, HP_HASHVAL, hashBytes, 0);

hashBytes是一个20字节的数组。

然而问题是这个HCRYPTHASH句柄产生的签名是不正确的。我将问题追溯到CAPI实际上不使用我的hashBytes数组中的所有20个字节的事实。由于某种原因,它认为SHA1只有4个字节。

为了验证这一点,我写了这个小程序:

HCRYPTPROV cryptoProvider;
CryptAcquireContext(&cryptoProvider, NULL, NULL, PROV_RSA_FULL, 0);

HCRYPTHASH hash;
HCRYPTKEY keyForHash;
CryptCreateHash(cryptoProvider, CALG_SHA1, keyForHash, 0, &hash);

DWORD hashLength;
CryptGetHashParam(hash, HP_HASHSIZE, NULL, &hashLength, 0);
printf("hashLength: %d\n", hashLength);

这打印出hashLength:4!

任何人都可以解释我做错了什么或为什么Microsoft CAPI认为SHA1是4字节(32位)而不是20字节(160位)。

2 个答案:

答案 0 :(得分:2)

您的代码中存在一个小错误。而不是

DWORD hashLength;
CryptGetHashParam(hash, HP_HASHSIZE, NULL, &hashLength, 0);
printf("hashLength: %d\n", hashLength);

你应该使用

DWORD hashLength, hashSize;
hashLength = sizeof(DWORD)
CryptGetHashParam(hash, HP_HASHSIZE, (PBYTE)&hashSize, &hashLength, 0);
printf("hashSize: %d\n", hashSize);

然后你将按预期收到20。

CryptSignHash之后CryptSetHashParam的使用情况也必须有效。请参阅http://msdn.microsoft.com/en-us/library/aa380270(VS.85).aspx CryptSetHashParam函数说明末尾的注释。我想你在检索签名结果时犯了与CryptGetHashParam(..., HP_HASHSIZE, ...)相同的错误。将您的代码与CryptSignHash函数http://msdn.microsoft.com/en-us/library/aa380280(VS.85).aspx的说明中的代码进行比较。

答案 1 :(得分:1)

我认为你不能以这种方式使用CryptCreateHash。来自MSDN

  

“CryptCreateHash功能   启动一个流的散列   数据“。

换句话说,看起来你不能以空的方式实例化哈希上下文(然后让它对你的输入数据进行哈希)。

你目前如何获得哈希 - 一个字节数组?如果是这样,你可能只想签署该数组;我会考虑CryptSignMessageCryptSignMessageWithKey来完成这项工作。

(我猜,但你所看到的可能是由于在哈希上下文完成某些工作之后,输出哈希长度没有被设置。)