C# · 12月 30, 2021

c# – SignedXml计算签名与SHA256

我正在尝试使用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();