使用SHA256的SignedXml计算签名
我正在尝试使用SHA256对XML文档进行数字签名。
I am trying to digitally sign a XML document using SHA256.
我正在尝试使用 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();
错误。有人可以告诉我我在做什么错吗?
But i am getting "Invalid algorithm specified." error at signedXml.ComputeSignature();
. Can anyone tell me what I am doing wrong?
X509Certificate2
加载从pfx文件到 Microsoft增强加密提供程序v1.0 中的私钥(提供程序类型 1
aka PROV_RSA_FULL
),不支持SHA-256。
X509Certificate2
loads the private key from the pfx file into the Microsoft Enhanced Cryptographic Provider v1.0 (provider type 1
a.k.a. PROV_RSA_FULL
) which doesn't support SHA-256.
基于CNG的密码提供程序(在Vista和Server 2008中引入)比CryptoAPI支持更多算法基于.NET的提供程序,但.NET代码似乎仍可与基于CryptoAPI的类一起使用,例如 RSACryptoServiceProvider
而不是 RSACng
因此我们必须解决这些限制。
The CNG-based cryptographic providers (introduced in Vista and Server 2008) support more algorithms than the CryptoAPI-based providers, but the .NET code still seems to be working with CryptoAPI-based classes like RSACryptoServiceProvider
rather than RSACng
so we have to work around these limitations.
但是,另一个CryptoAPI提供程序 Microsoft增强型RSA和AES加密提供程序(提供程序类型 24
aka PROV_RSA_AES
)确实支持SHA-256。因此,如果我们将私钥输入到此提供程序中,则可以对其进行签名。
However, another CryptoAPI provider, Microsoft Enhanced RSA and AES Cryptographic Provider (provider type 24
a.k.a. PROV_RSA_AES
) does support SHA-256. So if we get the private key into this provider, we can sign with it.
首先,您必须调整您的 X509Certificate2
构造函数,通过添加 X509KeyStorageFlags.Exportable $,使密钥可以从
X509Certificate2
放入的提供程序中导出。 c $ c>标志:
First, you'll have to adjust your X509Certificate2
constructor to enable the key to be exported out of the provider that X509Certificate2
puts it into by adding the X509KeyStorageFlags.Exportable
flag:
X509Certificate2 cert = new X509Certificate2(
@"location of pks file", "password",
X509KeyStorageFlags.Exportable);
并导出私钥:
var exportedKeyMaterial = cert.PrivateKey.ToXmlString(
/* includePrivateParameters = */ true);
然后为一个新的 RSACryptoServiceProvider
实例创建一个支持SHA-256的提供程序:
Then create a new RSACryptoServiceProvider
instance for a provider that supports SHA-256:
var key = new RSACryptoServiceProvider(
new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;
并将私钥导入到其中:
key.FromXmlString(exportedKeyMaterial);
创建 SignedXml
实例后,告诉它使用 key
而不是 cert.PrivateKey
:
When you've created your SignedXml
instance, tell it to use key
rather than cert.PrivateKey
:
signedXml.SigningKey = key;
现在可以使用了。
这是提供商类型列表和他们的代码在MSDN上。
以下是您示例的完整调整后代码:
Here's the full adjusted code for your example:
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();