草庐IT

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

coder 2024-07-03 原文

我在 .NET Framework 4.5 版中遇到了一个阻止程序来处理带有数字签名的 XML 签名。

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

我正在尝试使用 WSSE token 签署符合 Oasis ebms 标准的 SOAP 消息。请注意,该类(class)是为满足 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 元素或整个消息进行签名,但是我一直收到 Cryptography 异常,声称不支持 SHA-256。我认为这个异常不应该是有效的观察 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<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();
    }

似乎有效并在另一端验证 OK。前几天使用 Holodeck 进行了测试,我认为它在签名元素中缺少的时间戳上失败了。

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

关于C# 支持对单个 XML 元素进行 RSA SHA 256 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17258800/

有关C# 支持对单个 XML 元素进行 RSA SHA 256 签名的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  4. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  5. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  6. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  9. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  10. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

随机推荐