Dom*_*Eav 3 cryptography rsa sha256 cryptoapi digital-signature
我试图在Windows上生成数字签名(来自XP SP3,但目前正在使用Windows 7进行测试),其中CryptoAPI将与以下openssl命令兼容:
openssl dgst -sha256 -sign <parameters> (for signing)
openssl dgst -sha256 -verify <parameters> (for validation)
Run Code Online (Sandbox Code Playgroud)
我想使用Windows"MY"密钥库中的私钥进行签名.
我设法使用SHA1摘要算法使用以下CryptoAPI函数签署文件(为简洁省略参数):
CertOpenStore
CertFindCertificateInStore
CryptAcquireCertificatePrivateKey
CryptCreateHash (with CALG_SHA1)
CryptHashData
CryptSignHash
Run Code Online (Sandbox Code Playgroud)
生成的签名与"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
Run Code Online (Sandbox Code Playgroud)
不幸的是,这没有按预期工作:CryptGetUserKey失败,错误8009000D(NTE_NO_KEY).如果我删除了CryptGetUserKey调用,程序将一直运行,直到CryptSignHash失败,错误80090016(NTE_BAD_KEYSET).我知道密钥集确实存在并且工作正常,因为我能够使用它来签署SHA1摘要.
我尝试使用从CertFindCertificateInStore获得的证书上下文中的信息再次获取上下文:我能做的最好的是成功的CryptGetUserKey调用,但CryptSignHash总是会失败并出现相同的错误.
我试图使用的私钥是2048位长,但我不认为它是一个问题,因为它与SHA1摘要一起使用.我很茫然,所以任何建议都会非常受欢迎!
小智 9
80090008 是由于Base Provider不支持SHA256,SHA384和SHA512引起的,你必须使用 CryptAcquireContext(hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0);
小智 6
以前的大多数答案都包含真实答案的部分内容。这样做的方法是通过调用获取使用密钥容器和“Microsoft Enhanced RSA and AES Cryptographic Provider”的HCRYPTPROV
CryptAcquireContext(&hCryptProv, <keyContainerName>, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_SILENT)
Run Code Online (Sandbox Code Playgroud)
生成的 hCryptProv 可用于对使用所有支持的 SHA2 创建的哈希进行签名:256、384、512。
密钥容器名称可以通过 CertGetCertificateContextProperty() 获得,参数 CERT_KEY_PROV_INFO_PROP_ID 如果密钥是通过证书获得的,或者通过 CryptGetProvParam() 与参数 PP_CONTAINER 获得,如果该密钥已经有一个 HCRPYPTPROV(例如,通过 CryptAcquireCertificateCquire 获得)。
即使私钥不可导出,此技术也有效。