我正在尝试使用 SHA256 对 XML 文档进行数字签名。
我正在尝试使用 Security.Cryptography.dll为此。
这是我的代码-
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription),"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
X509Certificate2 cert = new X509Certificate2(@"location of pks file", "password");
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(@"input.xml");
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = cert.PrivateKey;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
//
// Add a signing reference, the uri is empty and so the whole document
// is signed.
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
signedXml.AddReference(reference);
//
// Add the certificate as key info, because of this the certificate
// with the public key will be added in the signature part.
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
// Generate the signature.
signedXml.ComputeSignature();
但我收到“指定的算法无效”。 signedXml.ComputeSignature();
处出错。谁能告诉我我做错了什么?
最佳答案
X509Certificate2
将私钥从 pfx 文件加载到 Microsoft Enhanced Cryptographic Provider v1.0(提供程序类型 1
又名 PROV_RSA_FULL
) 不支持 SHA-256。
基于 CNG 的加密提供程序(在 Vista 和 Server 2008 中引入)比基于 CryptoAPI 的提供程序支持更多的算法,但是 .NET 代码似乎仍然可以使用基于 CryptoAPI 的类,例如 RSACryptoServiceProvider
而不是 RSACng
,所以我们必须解决这些限制。
但是,另一个 CryptoAPI 提供程序 Microsoft Enhanced RSA and AES Cryptographic Provider(提供程序类型 24
a.k.a. PROV_RSA_AES
)确实支持 SHA-256。因此,如果我们将私钥输入该提供程序,我们就可以使用它进行签名。
首先,您必须调整您的 X509Certificate2
构造函数,使 key 能够从 X509Certificate2
通过添加 X509KeyStorageFlags.Exportable
标志:
X509Certificate2 cert = new X509Certificate2(
@"location of pks file", "password",
X509KeyStorageFlags.Exportable);
并导出私钥:
var exportedKeyMaterial = cert.PrivateKey.ToXmlString(
/* includePrivateParameters = */ true);
然后为支持 SHA-256 的提供商创建一个新的 RSACryptoServiceProvider
实例:
var key = new RSACryptoServiceProvider(
new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;
并将私钥导入其中:
key.FromXmlString(exportedKeyMaterial);
创建SignedXml
实例后,告诉它使用key
而不是cert.PrivateKey
:
signedXml.SigningKey = key;
它现在可以工作了。
这是 list of provider types and their codes在 MSDN 上。
这是您的示例的完整调整代码:
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
X509Certificate2 cert = new X509Certificate2(@"location of pks file", "password", X509KeyStorageFlags.Exportable);
// Export private key from cert.PrivateKey and import into a PROV_RSA_AES provider:
var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ true);
var key = new RSACryptoServiceProvider(new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;
key.FromXmlString(exportedKeyMaterial);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(@"input.xml");
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
//
// Add a signing reference, the uri is empty and so the whole document
// is signed.
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
signedXml.AddReference(reference);
//
// Add the certificate as key info, because of this the certificate
// with the public key will be added in the signature part.
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
// Generate the signature.
signedXml.ComputeSignature();
关于c# - SignedXml 使用 SHA256 计算签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29005876/