我正在尝试使用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文件加载到不支持SHA-256的Microsoft Enhanced Cryptographic Provider v1.0(提供商类型1 a.k.a. PROV_RSA_FULL)中.
基于CNG的加密提供程序(在Vista和Server 2008中引入)支持比基于CryptoAPI的提供程序更多的算法,但是.NET代码似乎还在使用基于CryptoAPI的类,如RSACryptoServiceProvider而不是RSACng,所以我们必须解决这些限制.
但是,另一个CryptoAPI提供程序,Microsoft增强型RSA和AES加密提供程序(提供者类型24 a.k.a. PROV_RSA_AES)支持SHA-256.所以如果我们把这个私钥加入这个提供者,我们可以用它签名.
首先,您必须调整X509Certificate2构造函数,以便将密钥从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实例时,请告诉它使用密钥而不是cert.PrivateKey:
signedXml.SigningKey = key;
它现在可以工作.
以下是MSDN上的list of provider types and their codes.
以下是您的示例的完整调整代码:
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription),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,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();