我正在尝试使用与以下 openssl 命令兼容的 CryptoAPI 在 Windows(来自 XP SP3,但目前正在使用 Windows 7 测试)上生成数字签名:
openssl dgst -sha256 -sign <parameters> (for signing)
openssl dgst -sha256 -verify <parameters> (for validation)
我想使用 Windows“MY”密钥库中的私钥进行签名。
我设法通过使用以下 CryptoAPI 函数(为简洁起见省略参数)使用 SHA1 摘要算法对文件进行签名:
CertOpenStore
CertFindCertificateInStore
CryptAcquireCertificatePrivateKey
CryptCreateHash (with CALG_SHA1)
CryptHashData
CryptSignHash
生成的签名与“openssl dgst -sha1 -verify”兼容(一旦字节顺序颠倒)。
我的问题是:当我尝试将 CALG_SHA_256 与 CryptCreateHash 一起使用时,它失败并出现错误 80090008 (NTE_BAD_ALGID)。通过谷歌搜索,我发现我需要使用特定的提供程序 (PROV_RSA_AES) 而不是默认的提供程序。因为我有一个提供者句柄,所以我还需要用 CryptGetUserKey 替换 CryptAcquireCertificatePrivateKey。所以我修改了我的程序看起来像:
CryptAcquireContext (with PROV_RSA_AES)
CertOpenStore
CertFindCertificateInStore
CryptGetUserKey
CryptCreateHash (with CALG_SHA256)
CryptHashData
CryptSignHash
不幸的是,这没有按预期工作:CryptGetUserKey 失败并出现错误 8009000D (NTE_NO_KEY)。如果我删除 CryptGetUserKey 调用,程序会一直运行到 CryptSignHash,它会失败并出现错误 80090016 (NTE_BAD_KEYSET)。我知道密钥集确实存在并且工作正常,因为我能够使用它来签署 SHA1 摘要。
我尝试使用从 CertFindCertificateInStore 获得的证书上下文中的信息再次获取上下文:我能做的最好的事情就是成功调用 CryptGetUserKey,但 CryptSignHash 总是会失败并出现相同的错误。
我尝试使用的私钥是 2048 位长,但我不认为它会成为问题,因为它适用于 SHA1 摘要。我很茫然,所以任何建议都会非常受欢迎!