无法从 .net x509certificate2 对象获取私钥到 bouncycastle AsymmetricCipherKeyPair

Unable to fetch private key from .net x509certificate2 object to bouncycastle AsymmetricCipherKeyPair

我试图从这段代码中获取 pkcs-7 签名X509Certificate2 对象的密钥对。

RSACryptoServiceProvider key = (RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaparam = key.ExportParameters(true);
AsymmetricCipherKeyPair keypair = DotNetUtilities.GetRsaKeyPair(rsaparam);

如果 X509Certificate2 对象是使用这样的 .pfx 文件创建的

X509Certificate2 cert = new X509Certificate2(".pfx file path", "password");

它工作正常。 但是当 证书像这样从证书存储中列出时

 X509Certificate2 cert;
 X509Store UserCertificateStore = new X509Store("My");
 UserCertificateStore.Open(OpenFlags.ReadOnly);
 var certificates = UserCertificateStore.Certificates;
 foreach (var certificate in certificates)
 {
    if (certificate.Thumbprint==thumbprint)
    {
       cert=certificate;
       break;
    }
 }

它抛出异常消息 - 密钥在指定状态下无效。

@Crypt32 回答后尝试使用 RSA 方法符号哈希

RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;

using (SHA256Managed sHA256 = new SHA256Managed())
{
    byte[] hash = sHA256.ComputeHash(data);
    return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
}

但签名不是 PKCS#7 格式

这是因为 BouncyCastle 尝试从 .NET 对象获取原始密钥 material(字面意思是导出),而实际密钥未标记为可导出。在 Windows 系统中,密钥存储在控制所有密钥操作的加密服务提供商中。当您需要执行特定的加密操作时,您是在要求 CSP 完成一项工作,而无需向您公开密钥 material。如果密钥在 CSP 中是 imported/generated 作为可导出的,您可以要求 CSP 导出密钥 material。如果没有设置这个标志,CSP 不会给你密钥。

我不知道 BouncyCastle 是如何工作的,但如果它需要原始密钥 material,那么您的证书中需要可导出的私钥。

要回答基本问题,"How do I make a PKCS#7 SignedData message signed with RSA+SHA-2-256?"

https://github.com/Microsoft/dotnet/blob/master/releases/net471/dotnet471-changes.md#bcl 表示 SHA-2-256 不仅适用于 4.7.1,而且现在是默认值:

Updated SignedXML and SignedCMS to use SHA256 as a default over SHA1. SHA1 may still be used by selected as a default by enabling a context switch. [397307, System.Security.dll, Bug]

在旧框架上可以通过:

ContentInfo content = new ContentInfo(data);
SignedCms cms = new SignedCms(content);
CmsSigner signer = new CmsSigner(cert);
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
cms.ComputeSignature(signer);
return cms.Encode();

其中“2.16.840.1.101.3.4.2.1”是 SHA-2-256 的 OID-ese。