CryptoAPI:使用 CryptVerifySignature 使用公钥验证来自 openssl 的签名
我正在尝试将 Mac 的 AquaticPrime 框架移植到 Windows。
在 Mac 上,它使用 opensll 库,我尝试了解如何将其移植到 Windows,我猜我必须使用 CryptoAPI。
我主要需要使用给定的公钥验证生成的签名的代码。
以下是使用 openssl 完成验证的方式:
- 输入:许可证数据、公钥和签名,均为 128 字节长。
- SHA1 摘要是根据许可证数据计算得出的。
- 使用公钥数据设置 RSA 上下文
- ,在给定 RSA 密钥和签名的情况下,调用 RSA_public_decrypt(),返回 20 字节长的 SHA1 摘要 - 如果此摘要等于步骤 2 中的摘要,则签名有效。
那么,我该如何使用 CryptoAPI 来做到这一点呢?我已经做到了这一点:
- 从 CryptAcquireContext(ctx, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) 开始,
- 在 此帖子,其中 pubexp=3 和 bitlen=1024。这一切都有效,即我没有收到任何错误,并且我查看了二进制数据以验证它是否与 MSDN 文章显示的内容相匹配。
- 从许可证数据创建 SHA1 摘要。我检索了生成的 20 字节哈希值,发现它与我在 Mac 上使用 openssl 得到的值相匹配。
此时,我调用:
CryptVerifySignature (hashHdl, sig, sigLen, keyHdl, 0, 0)
此操作失败,错误代码为 ERROR_INVALID_PARAMETER。
奇怪的是,当我第一次不小心将两倍大的公钥存储到 PUBLICKEYBLOB 结构中时,我收到了 NTE_BAD_SIGNATURE 错误。这可能表明现在我传递的公钥是正确的。
那么为什么现在会出现 ERROR_INVALID_PARAMETER 错误呢?我已经验证哈希值是正确的,并且密钥似乎也被接受。而“sig”参数只是一个指向签名的128字节的指针,sigLen是128。
那么,我在这里错过了什么?
I am trying to port the AquaticPrime framework for Mac to Windows.
On the Mac, it uses the opensll library, and I try to understand how to port this to Windows, where I have to use the CryptoAPI, I guess.
I mainly need the code for validation of the generated signature with a given public key.
Here's how verification is done with openssl:
- inputs: license data, public key and signature, both 128 bytes long.
- A SHA1 digest is calculated from the license data.
- A RSA context is set up with the public key data
- RSA_public_decrypt() is called, given the RSA key and the signature, which returns a 20 byte long SHA1 digest - is this digest equal the one from step 2, the signature is valid.
So, how do I do this with CryptoAPI? I've gotten this far:
- Start with CryptAcquireContext(ctx, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
- Use CryptImportKey with the help of this posting, with pubexp=3 and bitlen=1024. That all works, i.e. I get no errors, and I looked at the binary data to verify that it matches what the MSDN article shows.
- Create a SHA1 digest from the license data. I've retrieved the resulting 20 byte hash value and see that it matches what I get with openssl on the Mac.
At this point, I call:
CryptVerifySignature (hashHdl, sig, sigLen, keyHdl, 0, 0)
This fails with error code ERROR_INVALID_PARAMETER.
The odd thing is that when I first accidentally had stored a twice as large public key into the PUBLICKEYBLOB structure, I received a NTE_BAD_SIGNATURE error instead. This might suggest that now the public key I am passing is correct.
Why the ERROR_INVALID_PARAMETER error now, then? I've verified that the hash value is correct, and the key appears to be accepted, too. And the "sig" parameter is just a pointer to the 128 bytes of the signature, and sigLen is 128.
So, what am I missing here?
好的,经过多次尝试和错误,我解决了这个问题。
签名和公钥数据在采用纯字节字符串形式时都需要反转,即第一个字节到最后一个位置,依此类推。
然后上面的工作就完成了。
OK, I solved the problem after lots of trial-and-error.
Both the signature and the public key data, when in their pure byte string form, need to be reversed, i.e. first byte to last position, and so on.
Then the above works.