使用 SHA256 签名 XML

Signing XML with SHA256 working when it should not

问这个问题很奇怪,但我会试试的。

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

SignedXml.CheckSignature Method (X509Certificate2, Boolean) -> Examples section
https://msdn.microsoft.com/en-us/library/ms148731(v=vs.110).aspx#Anchor_3

之后要求改成SHA256算法。我使用那些页面中的代码来改编原始代码,并且它工作正常,当时我使用 4.6 作为目标框架:

Using SHA256 with the SignedXml Class
https://blogs.msdn.microsoft.com/winsdk/2015/11/14/using-sha256-with-the-signedxml-class/

.net Framework 4.6.2 adds support to sign XML Documents using RSA-SHA256
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 class 仅在框架 4.5 之后可用,因此我必须编写自己的版本,正如我在某些网页中看到的那样。

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

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

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

有人知道发生了什么事吗?

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

由于 WinXP 没有 4.6.2,您需要自己添加处理程序。针对 XP 拥有的任何框架都会将您限制在可用的 API 范围内,尽管正如您所见,运行时的行为可能有所不同,因此您确实应该在目标 OS.[=10= 上进行测试]

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

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

Common Language Runtime (CLR) - Versions of the Common Language Runtime
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 Versioning and Multi-Targeting - .NET 4.5 is an in-place upgrade to .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 安装程序已经安装了,那个可能把最后一个框架放在了机器上),当我真的失败时,这并不奇怪在 Windows XP SP3 下执行应用程序。但现在我完全知道该怎么做了。