【问题标题】:Signing XML with SHA256 working when it should not在不应该使用 SHA256 的情况下使用 SHA256 签名 XML
【发布时间】:2018-01-05 00:57:48
【问题描述】:

这是一个奇怪的问题,但我会尝试。

我使用目标框架 4.5.2 开始我的项目,要求是使用 SHA1 算法签署 XML 文件。我使用了这个 MSDN 页面中的示例,效果很好:

SignedXml.CheckSignature 方法 (X509Certificate2, Boolean) -> 示例部分
https://msdn.microsoft.com/en-us/library/ms148731(v=vs.110).aspx#Anchor_3

之后,要求改为 SHA256 算法。我使用那些页面中的代码来修改原始代码,并且效果很好,那时我使用 4.6 作为目标框架:

将 SHA256 与 SignedXml 类一起使用
https://blogs.msdn.microsoft.com/winsdk/2015/11/14/using-sha256-with-the-signedxml-class/

.net Framework 4.6.2 增加了对使用 RSA-SHA256 签署 XML 文档的支持
https://www.stum.de/2016/05/19/net-framework-4-6-2-adds-support-to-sign-xml-documents-using-rsa-sha256/

然后我发现 4.6.2 版框架添加了对 SHA256 的完全支持,并且不再需要 CryptoConfig.AddAlgorithm() 调用。我将项目更改为 4.6.2 版,进行了所需的更改,注释了 CryptoConfig.AddAlgorithm() 调用,它工作得很好。

但是现在我们有另一个需求变化:我们希望我们的软件在 Windows XP 下运行(是的,我们确实有用户仍在使用它),并且最后一个可以在 XP (SP3) 上运行的框架版本是 v4.0。因此,我需要测试使用 SHA256 签署 XML 文件是否适用于框架 4.0。

然后我将目标框架更改为 v4.0 并开始更改。我在 CryptoConfig.AddAlgorithm() 调用中使用的 RSAPKCS1SHA256SignatureDescription 类仅从框架 4.5 开始可用,因此我必须编写自己的版本,正如我在某些网页中看到的那样。

但是,现在奇怪了。我保留了 CryptoConfig.AddAlgorithm() 调用的注释以查看会发生什么,因此我可以编写自定义类,但是,它只是工作!

我认为 CryptoConfig.AddAlgorithm() 已经在项目的某处或我的机器中注册了算法。我对此进行了研究,但一无所获。所以我在另一台机器上尝试了,它也可以工作,但是那台机器之前可能已经执行过之前的代码,所以它也可以注册算法。我尝试了另一台机器,我不确定,但也在那里工作。

所以,我去了一台从未见过该项目的机器,当时我编译它并部署了可执行文件(我正在其他机器上执行 VS 项目)。我在那台机器上删除了 4.0 之后的所有 .NET 框架并尝试运行该应用程序。而且......它仍然有效!它使用 SHA256 对 XML 进行签名,并且工作正常。所有这些机器都运行 Windows 10。

有人知道发生了什么吗?

【问题讨论】:

  • 加密算法通常会向后移植到旧版本以保持兼容性。这可能是一个非常简单的答案。如果您安装 Windows XP 和第一个可分发的 4.0,它可能会失败。请注意,Microsoft 有不保留/显示真实版本信息的讨厌习惯(4.0.0 和 4.0.999 的文件可能具有相同的文件名,仅以最后更改日期区分)。
  • 但真正奇怪的是,当我开始将代码改编为 SHA256 时,如果没有 CryptoConfig.AddAlgorithm () 调用,它就无法工作。我正在使用框架 4.6。现在,有了框架 4.0,它就可以工作了。我会这样做,创建一个安装干净的 Windows XP SP3 的虚拟机,然后看看会发生什么。

标签: .net xml cryptography sha256


【解决方案1】:

您的目标版本和您正在运行的版本不同。任何目标 4.0-4.7 都在 4.7 运行时上运行。由于添加支持是非破坏性的,因此没有通过目标版本回退来完成。

由于 WinXP 没有 4.6.2,您需要自己添加处理程序。以 XP 的任何框架为目标都会限制您使用可用的 API,尽管您已经看到运行时的行为可能会有所不同,因此您确实应该在目标操作系统上进行测试。

【讨论】:

  • 你的意思是,即使我的目标是 4.0 版,而且我的机器上确实有 4.0 版,但机器上也有 4.7 版,它可能在我的项目上运行 4.7 版而不是 4.0 版?但是,为什么在我更改框架版本后对 X509Certicate2.GetRSAPrivateKey() 方法的调用停止工作?为什么我的应用程序的编译版本可以在我卸载了所有 4.0 以上版本的机器上运行?这对我来说仍然没有意义!
  • 有没有办法在运行时检查我的应用程序正在使用哪个版本的框架?
【解决方案2】:

Marteen Bodewes 评论和 bartonjs 回答之后,我做了一些研究并了解了一些关于 .NET Framework 的知识。过去,我确实购买了有关 .NET 并行功能的 Microsoft 营销,但我一直认为该框架的每个版本都将在同一台机器上一起存在。今天我了解到情况并非完全如此。

首先,CLR 和框架是不同的东西,不一定要一起使用。公共语言运行时 (CLR) 是框架中判断是否存在并行共存的关键部分。到今天为止,只有 4 个版本的 CLR:1.0、1.1、2.0 和 4:

公共语言运行时 (CLR) - 公共语言运行时的版本
https://docs.microsoft.com/en-us/dotnet/standard/clr#versions-of-the-common-language-runtime

共享相同 CLR 版本的所有框架版本都将就地替换之前的版本。因此,如果您的机器上只有 Framework 2.0,那么您就有 CLR 2.0 和 Framework 2.0。如果您在那台机器上安装了 Framework 3.5,您仍然拥有 CLR 2.0,但 Framework 2.0 被 3.5 版本取代。之后,如果您安装 Framework 4.0,您将拥有 CLR 2.0 和 CLR 4 以及 Framework 3.5 和 Framework 4.0。如果您在同一台机器上安装 Framework 4.5,您仍然拥有 CLR 4,但现在 Framework 4.0 已被 4.5 版本取代。

这就是为什么,至少在我的机器上,'C:\Windows\assembly' 路径下只有 v2.0 和 v4.0 文件夹。我注意到,在运行时,.NET DLL 是从该路径加载的。不过,我不确定“C:\Windows\Microsoft.NET\Framework”的目的是什么。

但这并没有回答我向 bartonjs 提出的问题:如果新版本的框架消失了与该机器共享相同 CLR 的先前版本,Visual Studio 如何知道哪些类、方法、属性等是是否适用于为项目选择的特定目标框架?

所以我发现了 Scott Hanselman 的这篇出色的文章:

.NET 版本控制和多目标 - .NET 4.5 是对 .NET 4.0 的就地升级
https://www.hanselman.com/blog/NETVersioningAndMultiTargetingNET45IsAnInplaceUpgradeToNET40.aspx

答案是:'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework' 目录下是通过机器的所有版本的存档,Visual Studio 使用这些存档! (为什么不把所有这些东西都放在一个地方,然后真正并排共存呢?)

在所有这些答案之后,我更好地理解了发生了什么(顺便说一下,我发现最后一台机器确实安装了框架 4.7,因为我卸载了所有这些,但我打算在上面安装 Visual Studio Community 2017 ,并取消了我的测试,但是,Visual Studio Installer 已经安装了,那个可能把最后一个框架放在了机器上),当我在 Windows XP SP3 下执行应用程序时它真的失败了,这并不奇怪。但现在我确切地知道该怎么做了。

【讨论】:

    猜你喜欢
    • 2012-05-27
    • 2023-03-10
    • 1970-01-01
    • 2019-02-14
    • 2012-01-19
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多