X509Certificate2,具有使用SHA256withRSA的私钥签名数据

时间:2018-11-23 15:12:02

标签: c# .net cryptography

这与X509Certificate2 from store with private key的答案有关。

似乎当我想使用SHA256withRSA时,不能直接从证书的私钥中使用服务提供商-我需要创建新的加密服务提供商:

  var bytes = new byte[] { 0, 1, 2, 3 };

  //_cert - X509Certificate2 with private key
  //csp1 is of type I need, but it won't work
  var csp1 = _cert.PrivateKey as RSACryptoServiceProvider;

  var cspParameters = new CspParameters
  {
    KeyContainerName = csp1.CspKeyContainerInfo.KeyContainerName,
    KeyNumber = csp1.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2,
  };

  var csp2 = new RSACryptoServiceProvider(cspParameters);

  //I can't use csp1 here - will throw "CryptographicException : Invalid algorithm specified."
  //I can use csp1 with "SHA1" though
  var signature = csp2.SignData(bytes, CryptoConfig.MapNameToOID("SHA256"));

我在这里找到了一些有关此的信息:

https://blogs.msdn.microsoft.com/shawnfa/2008/08/25/using-rsacryptoserviceprovider-for-rsa-sha256-signatures/

但是上面的解决方案来自注释部分,我真的不明白为什么我需要跳过篮球才能使用一种常见算法。所以我想问的是:

  • 为什么csp1不能完全与SHA256一起使用?
  • 像我一样创建csp2是否正确?
  • 是否可以在.NET中实现更好/更新的方式?

如果需要,可以如下生成带有私钥的证书:

openssl req -x509 -sha256 -newkey rsa:2048 -keyout ./temp/key.key -out ./temp/crt.crt -days 10 –nodes
openssl pkcs12 -export -out .\temp\cert.pfx -inkey .\temp\key.key –in .\temp\crt.crt

1 个答案:

答案 0 :(得分:2)

这完全取决于您的证书来自何处。就像MSDN注释所说的那样,如果它来自Microsoft Base Cryptographic Provider,那么它将不能与SHA256一起使用。该CSP早在1996年就随CryptoAPI的第一个版本一起发布,并且不了解SHA256,因为当时还没有SHA256。

优雅地检查和处理此问题的方法是:

public byte[] SignData(RSACryptoServiceProvider csp, byte[] bytes)
{
    byte[] sig = null;
    if ((csp.CspKeyContainerInfo.ProviderType == PROV_RSA_FULL || csp.CspKeyContainerInfo.ProviderType == PROV_RSA_SCHANNEL) && !csp.CspKeyContainerInfo.HardwareDevice)
    {
        var cspParameters = new CspParameters
        {
            KeyContainerName = csp.CspKeyContainerInfo.KeyContainerName,
            KeyNumber = csp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2,
        };
        using (var csp2 = new RSACryptoServiceProvider(cspParameters))
        {
            sig = csp2.SignData(bytes, CryptoConfig.MapNameToOID("SHA256"));
        }
    }
    else {
        sig = csp.SignData(bytes, CryptoConfig.MapNameToOID("SHA256"));
    }
    return sig;
}

仅供参考,CryptoAPI是being deprecated,赞成Cryptography API: Next Generation。使用C#中的CNG进行操作的一种方法是使用System.Security.Cryptography.Cng

...
using (RSA rsa = new RSACng())
{
    byte[] signature = rsa.SignData(message, hashAlgorithm, paddingMode);
    ...
}