c# - X509Certificate2 与使用 SHA256withRSA 的私钥签名数据
问题描述
这与store with private key 对 X509Certificate2的答案有点相关。
似乎当我想使用 SHA256withRSA 时,我不能直接从证书的 PrivateKey 使用服务提供者——我需要创建新的加密服务提供者:
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"));
我在这里找到了一些关于此的信息:
但是上面的解决方案取自评论部分,我真的不明白为什么我需要跳过箍来使用一种常见的算法。所以我想问的是:
- 为什么
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
解决方案
这完全取决于您的证书来自哪里。就像 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被弃用,取而代之的是Cryptography API: Next Generation。在 C# 中使用 CNG 做你想做的事情的一种方法是使用System.Security.Cryptography.Cng:
...
using (RSA rsa = new RSACng())
{
byte[] signature = rsa.SignData(message, hashAlgorithm, paddingMode);
...
}
推荐阅读
- json - 通过 Logstash 将 JSON 从 CouchDB 解析到 ElasticSearch
- c++ - 使用指针作为模板参数
- c# - Blend-Tree 动画则相反
- node.js - 使用无服务器功能压缩照片文件夹的最有效方法是什么?
- kubernetes - 多个 Kubernetes 集群的状态仪表板
- java - Eclipse RCP 应用程序(使用 p2 存储库)使用 Ant 构建自动化
- terragrunt - 调用 sops_decrypt_file() 时来自 Terragrunt 的错误
- terminal - 如何在生产中检查终端中的输出
- ios - utf16Offset(in:)的in标签有什么用
- css - CSS 3使圆形底部阴影充满