C#支持对单个XML元素进行RSA SHA 256签名

我遇到过使用.NET Framework 4.5版的阻止程序来处理带有数字签名的XML。

我的问题是基于使用RSA SHA-256算法使用X.509证书签署单个XML元素的需要。 我已经阅读了很多关于这个主题的.NETpost,看来最初在CLR安全项目RSAPKCS1SHA256SignatureDescription.cs类中开发了一个解决方案。 RSAPKCS1SHA256SignatureDescription当然已经被整合到.net运行时中,从.NET 4.5开始,现在可以在分布式二进制System.Deployment.dll下使用。 我尝试在.NET中使用RSA SHA-256对特定的XML元素进行签名,但是还没有取得任何成功。

我正在尝试使用WSSE令牌签署符合Oasis ebms标准的SOAP消息。 请注意,该课程是为了满足Soap With Attachments(SwA)和签署个人附件而编写的。 我的代码如下

我的代码如下:

using System; using System.Collections.Generic; using System.IO; using System.IdentityModel.Tokens; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.ServiceModel.Channels; using System.ServiceModel.Security; using System.Text; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; using System.Deployment.Internal.CodeSigning; namespace TestCSharpX509CertificateRSSHA256 { public class SignatureSupportUtility { private bool IsSignatureContentTransform { get { return true; //get IsSignatureContentTransform } } public SignatureSupportUtility() { Register(); } private static void Register() { CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); } private void Sign(Message message, string[] elementIdsToSign, string[] attachmentsToSign, string wssNamespace, X509Certificate2 certificate) { //Prepare XML to encrypt and sign var element = this.PrepareEncyrptSign(message); bool signEntireDocument = true; string elementToBeSigned = string.Empty; var signedMessage = new XmlDocument(); signedMessage.AppendChild(signedMessage.ImportNode(element, true)); SignatureType signAs = SignatureType.InternallyDetached; signedMessage.PreserveWhitespace = false; OverrideSignedXml signedXml = new OverrideSignedXml(signedMessage); signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; if (elementIdsToSign != null && elementIdsToSign.Length > 0) { bool isContentTransform = this.IsSignatureContentTransform; foreach (string s in elementIdsToSign) { // Create a reference to be signed. Reference reference = new Reference(string.Format("#{0}", s)); reference.AddTransform(new XmlDsigExcC14NTransform()); reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; // Add the reference to the SignedXml object. signedXml.AddReference(reference); } signEntireDocument = false; } // Reference attachments to sign if (attachmentsToSign != null && attachmentsToSign.Length > 0) { bool isContentTransform = this.IsSignatureContentTransform; foreach (string attachmentId in attachmentsToSign) { // Create a reference to be signed. Reference reference = new Reference(string.Format("{0}{1}", Constants.CidUriScheme, attachmentId)); reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; if (isContentTransform) { AttachmentContentSignatureTransform env = new AttachmentContentSignatureTransform(); reference.AddTransform(env); } else { AttachmentCompleteSignatureTransform env = new AttachmentCompleteSignatureTransform(); reference.AddTransform(env); } // Add the reference to the SignedXml object. signedXml.AddReference(reference); } signEntireDocument = false; } if (signEntireDocument) { Reference reference = new Reference(); reference.Uri = ""; reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); signedXml.AddReference(reference); signAs = SignatureType.Enveloped; } string x509CertificateReferenceId = string.Format("{0}-{1}", Constants.IdAttributeName, Guid.NewGuid().ToString("N")); KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509SecurityTokenReference(string.Format("#{0}", x509CertificateReferenceId), wssNamespace)); signedXml.KeyInfo = keyInfo; signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; RSA key = (RSACryptoServiceProvider)certificate.PrivateKey; signedXML.SigningKey = key; CidWebRequest.Message = message; signedXml.ComputeSignature(); var xmlSignature = signedXml.GetXml(); XmlDocument unsignedEnvelopeDoc = new XmlDocument(); unsignedEnvelopeDoc.LoadXml(message.MessageAsString); }}} 
 using System; using System.Collections.Generic; using System.IO; using System.IdentityModel.Tokens; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.Xml; using System.ServiceModel.Channels; using System.ServiceModel.Security; using System.Text; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; using System.Deployment.Internal.CodeSigning; namespace TestCSharpX509CertificateRSSHA256 { public sealed class OverrideSignedXml : SignedXml { public OverrideSignedXml() : base() { } public OverrideSignedXml(XmlDocument doc) : base(doc) { } public override XmlElement GetIdElement(XmlDocument document, string idValue) { XmlElement element = base.GetIdElement(document, idValue); if (element == null) { XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable); nsmgr.AddNamespace("wsu", ="http://docs.oasis-open. org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); element = document.SelectSingleNode("//*[@wsu:Id=\"" + idValue + "\"]", nsmgr) as XmlElement; } return element; } } 

}

我的SignatureSupportUtility类中的Sign方法应该足以签署单个XML元素或整个消息,但是我一直收到一个声明不支持SHA-256的Cryptographyexception。 我认为此exception不应该是有效的观察RSAPKCS1SHA256SignatureDescription.cs已注册。 但是,观察SignedXML类不包含SHA-256的命名空间而只包含SHA-128我开始怀疑是否支持SHA 256而不管注册。

有人可以告诉我如何最好地解决我的问题,并能够通过RSA SHA 256算法使用X.509证书签署XML吗?

我也在看Oasis ebms的东西。

我找不到我从中获取的文章,但我使用的是4.5中的类:

 public class RsaPkCs1Sha256SignatureDescription : SignatureDescription { public RsaPkCs1Sha256SignatureDescription() { KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider"; DigestAlgorithm = "System.Security.Cryptography.SHA256Managed"; FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter"; DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter"; } public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { var asymmetricSignatureDeformatter = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm); asymmetricSignatureDeformatter.SetKey(key); asymmetricSignatureDeformatter.SetHashAlgorithm("SHA256"); return asymmetricSignatureDeformatter; } 

然后用这样的东西签名(编辑了一些不相关的位):

  public XmlElement SignDocument(XmlDocument doc, List idsToSign) { CryptoConfig.AddAlgorithm(typeof(RsaPkCs1Sha256SignatureDescription), @"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); var cspParams = new CspParameters(24) { KeyContainerName = "XML_DISG_RSA_KEY" }; var key = new RSACryptoServiceProvider(cspParams); key.FromXmlString(_x509SecurityToken.Certificate.PrivateKey.ToXmlString(true)); var signer = new SoapSignedXml(doc) { SigningKey = key }; signer.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; var keyInfo = new KeyInfo(); keyInfo.AddClause(new SecurityTokenReference(_x509SecurityToken, SecurityTokenReference.SerializationOptions.Embedded)); signer.KeyInfo = keyInfo; signer.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; var cn14Transform = new XmlDsigExcC14NTransform(); string referenceDigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256"; foreach (string id in idsToSign) { var reference = new Reference("#" + id); reference.AddTransform(cn14Transform); reference.DigestMethod = referenceDigestMethod; signer.AddReference(reference); } signer.ComputeSignature(); return signer.GetXml(); } 

似乎工作,并在另一端validation确定。 前几天与Holodeck进行了测试,我认为它在签名元素中缺少的时间戳上失败了。

但是,附件的签名似乎是.NET中的一个真正问题 – 我认为根本不支持相关的转换。

不幸的是,当无法导出私钥时,Andrew的答案不适用。

我使用的是智能卡,到目前为止,我发现没有办法将SignedXML与SHA-256一起使用。 在RSACryptoServiceProvider的当前实现中,此function似乎已被破坏。

我认为唯一的解决方案是从CSP切换到PKCS#11,然后使用BouncyCastle.Net。 并重写一切。