简体   繁体   English

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

[英]C# Support for RSA SHA 256 signing for individual XML elements

I have encountered a blocker with the .NET Framework version 4.5 to do with signing of XML with digital signatures. 我遇到过使用.NET Framework 4.5版的阻止程序来处理带有数字签名的XML。

My problem is based around the need to sign individual XML elements with X.509 certificate with the RSA SHA-256 algorithm. 我的问题是基于使用RSA SHA-256算法使用X.509证书签署单个XML元素的需要。 I have read many .NET posts on this topic and it appears that there is a solution originally developed in the CLR Security project RSAPKCS1SHA256SignatureDescription.cs class. 我已经阅读了很多关于这个主题的.NET帖子,看来最初在CLR安全项目RSAPKCS1SHA256SignatureDescription.cs类中开发了一个解决方案。 RSAPKCS1SHA256SignatureDescription has of course since been incorporated into the .net runtime and as of .NET 4.5 is now available under the distributed binary System.Deployment.dll. RSAPKCS1SHA256SignatureDescription当然已经被整合到.net运行时中,从.NET 4.5开始,现在可以在分布式二进制System.Deployment.dll下使用。 I have attempted the above solution in .NET to sign specific XML elements with RSA SHA-256 however have yet to have any success. 我在.NET中尝试使用RSA SHA-256对特定的XML元素进行签名,但是还没有取得任何成功。

I am trying to sign a SOAP message complying with the Oasis ebms standard with a WSSE Token. 我正在尝试使用WSSE令牌签署符合Oasis ebms标准的SOAP消息。 Please be aware that the class is written to cater for Soap With Attachments (SwA) and signing individual attachments. 请注意,该课程的目的是为了满足Soap With Attachments(SwA)和签署个人附件。 My code is as follows 我的代码如下

My code is the following: 我的代码如下:

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;
    }
}

} }

The Sign method in my SignatureSupportUtility class should be adequate to sign individual XML elements or the whole message, however I keep receiving a Cryptography exception claiming that the SHA-256 is not supported. 我的SignatureSupportUtility类中的Sign方法应该足以签署单个XML元素或整个消息,但是我一直收到一个声明不支持SHA-256的Cryptography异常。 I think this exception should not be valid observing that the RSAPKCS1SHA256SignatureDescription.cs is registered. 我认为此异常不应该是有效的观察RSAPKCS1SHA256SignatureDescription.cs已注册。 However observing that the SignedXML class does not include the namespace for SHA-256 and only SHA-128 I am beginning to doubt if the SHA 256 is supported regardless of registration. 但是,观察SignedXML类不包含SHA-256的命名空间而只包含SHA-128我开始怀疑是否支持SHA 256而不管注册。

Could someone please advise me on how best to resolve my issue and be able to sign XML with an X.509 certificate via RSA SHA 256 algorithm? 有人可以告诉我如何最好地解决我的问题,并能够通过RSA SHA 256算法使用X.509证书签署XML?

I am also looking at the Oasis ebms stuff. 我也在看Oasis ebms的东西。

I cannot find the article I took this from but I used that class that is in 4.5: 我找不到我从中获取的文章,但我使用的是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;
    }

and then use something like this to sign (have edited some irrelevant bits out): 然后用这样的东西签名(编辑了一些不相关的位):

    public XmlElement SignDocument(XmlDocument doc, List<string> 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();
    }

seems to work and verifies OK at the other end. 似乎工作并在另一端验证确定。 Tested with Holodeck the other day and I think it failed on a timestamp that was missing from the signature elements. 前几天使用Holodeck进行了测试,我认为它在签名元素中缺少的时间戳上失败了。

However, the signing of attachments seems to be a real problem in .NET - I don't think the relevant transforms are supported at all. 但是,附件的签名似乎是.NET中的一个真正问题 - 我认为根本不支持相关的转换。

Unfortunately Andrew's answer is not applicable when the private key cannot be exported. 不幸的是,当无法导出私钥时,Andrew的答案不适用。

I am using a smart-card and so far I have found no way of using SignedXML with SHA-256. 我使用的是智能卡,到目前为止,我发现没有办法使用带有SHA-256的SignedXML。 This feature seems to be broken in the current implementation of RSACryptoServiceProvider. 在RSACryptoServiceProvider的当前实现中,此功能似乎已被破坏。

The only solution in my opinion would be to switch from CSP to PKCS#11 and then use BouncyCastle.Net. 我认为唯一的解决方案是从CSP切换到PKCS#11,然后使用BouncyCastle.Net。 And rewrite everything. 并重写一切。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#SHA256 RSA签名。 如何从byte []符号中提取字符串? - C# SHA256 RSA Signing. How to take a string from byte[] sign? 使用 SHA-256 哈希算法使用 PSS 填充和 MGF1 掩码的 C# RSA 签名 - C# RSA signing with PSS padding and a MGF1 mask using a SHA-256 hash algorithm 验证 C# 中的 RSA SHA256 签名 - Verify RSA SHA256 signature in C# 使用RSA-SHA256签名方法问题签署Xml文档 - Signing an Xml Document using RSA-SHA256 signature method issue C#计算SEPA(XML)支付文件的SHA256值 - C# Calculate SHA256 value for SEPA (XML) paymentfile 使用公钥进行 RSA-SHA256 解密所需的 C# 代码 - C# code needed for RSA-SHA256 decryption with public key RSACryptoServiceProvider(.NET的RSA)可以使用SHA256进行加密(不签名)而不是SHA1吗? - Can RSACryptoServiceProvider (.NET's RSA) use SHA256 for encryption (not signing) instead of SHA1? 在.NET Framework 4.0中使用SHA256签名XML算法 - Use SHA256 Signing XML algorithm in .NET Framework 4.0 是否可以处理C#中的单个位? 尝试实现SHA256生成器 - Is it possible to deal with individual bits in C#? Trying to implement a SHA256 generator 使用RSA签名文档时应用SHA-256 / SHA-512而不是SHA-1时程序崩溃 - Program crashing when Applying SHA-256/SHA-512 instead of SHA-1 when signing documents with RSA
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM