.NET框架更新后,EncryptedXml DecryptDocument方法出现错误。

11

我有一个旧的函数,是在2013年编写的,它可以解密另一个程序加密的xml文件。

这段代码非常简单。

        public static void Decrypt(XmlDocument Doc)
    {
        // Check the arguments.  
        if (Doc == null)
            throw new ArgumentNullException("Doc");

        // Create a new EncryptedXml object.
        EncryptedXml exml = new EncryptedXml(Doc);

        // Decrypt the XML document.
        exml.DecryptDocument();

    }

它之前一直非常好用,但最近我们的一些客户开始升级他们的4.6.2框架,所以DecryptDocument()方法停止工作了。现在它会抛出一个异常“算法组''无效”。如果我删除.net framework 4.6.2,它就又可以工作了。

这个链接中的示例代码会再现此错误,它会成功加密然后无法解密。

我正在使用A3证书,U盘令牌。有人遇到过这个问题吗?在.net 4.6.2中有任何解决方法吗?

编辑1:

堆栈跟踪:

at System.Security.Cryptography.CngAlgorithmGroup..ctor(String algorithmGroup) at System.Security.Cryptography.CngKey.get_AlgorithmGroup() at System.Security.Cryptography.RSACng..ctor(CngKey key) at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate) at System.Security.Cryptography.CngLightup.GetRSAPrivateKey(X509Certificate2 cert) at System.Security.Cryptography.Xml.EncryptedXml.DecryptEncryptedKey(EncryptedKey encryptedKey) at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri) at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument() at Criptografar.Program.Decrypt(XmlDocument Doc) in C:\Users\leoka\Documents\Visual Studio 2017\Projects\ConsoleApp4\Criptografar\Program.cs:line 152 at Criptografar.Program.Main(String[] args) in C:\Users\leoka\Documents\Visual Studio 2017\Projects\ConsoleApp4\Criptografar\Program.cs:line 83


1
你有完整的堆栈跟踪吗? - Maarten Bodewes
客户端是否进行了完整的重建?请让客户在项目中复制 bin 文件夹。然后删除 bin 文件夹并重新编译。我怀疑错误是由于编译器中的依赖关系引起的。编译器没有任何与 Net 版本相关的依赖关系,因此当安装新的 Net 版本时,需要进行完整的重新编译。编译器不会自动执行完整的编译。 - jdweng
@jdweng,即使在我的开发机器上也失败了,我开始了一个新项目,从这个链接中复制了示例代码。它无法解密。 - Leonardo Xavier
我会首先比较 .proj 文件(它们是 ASCII 格式)以确保没有更改设置。VS 2013 更改了许多默认设置。VS2013 将字符编码的默认值从 UTF8 更改为 Unicode,这可能解释了问题所在。我认为问题出在 VS 而不是 Net 库上。只需更改 Net 库并完全重建项目即可解决问题。偶尔 Microsoft 在升级 Net 时更改默认设置,但这是不寻常的。 - jdweng
尝试在加密过程中进行调试,通过创建一个变量并赋值为 cert.GetRSAPrivateKey()。在其中告诉我们 .Key.Algorithm.Key.AlgorithmGroup.Key.Provider 的相应值是什么。 - silkfire
显示剩余5条评论
3个回答

2

我自己无法重现这个问题 - 我没有“pendrive token”,我怀疑这就是问题所在 - 所以这只是猜测。Windows有两代加密API - 旧版API新一代API,即CNG。 现在,如果你查看你的堆栈跟踪中间出现的CngLightup类型的源代码,特别是DetectRsaCngSupport方法,你会发现.NET框架尝试使用新一代API(如果可能的话)。我的猜测是“pendrive token”设备不支持新API。你可以通过强制使用旧API来验证这一点。不幸的是,似乎没有公共配置标志来控制这一点,因此你必须采用反射式黑客攻击。例如,你可以在程序的开头放置以下内容,以便在尝试解密操作之前运行一次:

    var cngLightupType = typeof(EncryptedXml).Assembly.GetType("System.Security.Cryptography.CngLightup");
    var preferRsaCngField = cngLightupType.GetField("s_preferRsaCng", BindingFlags.Static | BindingFlags.NonPublic);
    var getRsaPublicKeyField = cngLightupType.GetField("s_getRsaPublicKey", BindingFlags.Static | BindingFlags.NonPublic);
    var getRsaPrivateKeyField = cngLightupType.GetField("s_getRsaPrivateKey", BindingFlags.Static | BindingFlags.NonPublic);
    preferRsaCngField.SetValue(null, new Lazy<bool>(() => false));
    getRsaPublicKeyField.SetValue(null, null);
    getRsaPrivateKeyField.SetValue(null, null);

请注意,这种方法非常粗糙,不具备线程安全性,省略了错误处理等。如果您确定CNG的使用是问题所在,那么您可以向“pendrive token”供应商请求提供与CNG兼容的驱动程序。或者您可以采用上述方法并进行改写以提高安全性。


非常感谢,我已经测试过了,它可以正常工作。现在我知道了问题出在哪里,所以我可以更深入地探究。这种方法可以为我赢得一些时间,以寻找更好的解决方案,如果有的话。 - Leonardo Xavier

2

谢谢提供信息,但是这个链接并没有说明不能使用A3证书进行解密。通过@silkfire的评论,我发现即使是RSAPrivateKey实例也无法获取。我不认为这是令牌制造商的问题,因为使用不同令牌的多个客户都报告了相同的问题。此外,它也没有指出如何解决这个问题。 - Leonardo Xavier

0
今天我遇到了一个非常相似的问题,结果发现是 .NET 4.6.2 中的一个 bug: https://github.com/Microsoft/dotnet/issues/341 根据这个问题,有两种解决方法:

1)将操作系统升级到 Windows Server 2012R2 或更高版本,2)加载用户配置文件。


1
感谢您的建议。我安装了一个带有Windows Server 2012R2的虚拟机,应用了所有的Windows更新,但它仍然无法与.NET Framework 4.6.2兼容。我正在使用桌面应用程序,因此配置IIS以加载用户配置文件并不适合。 - Leonardo Xavier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接