.Net 框架更新后 EncryptedXml DecryptDocument 方法错误

EncryptedXml DecryptDocument method error after .Net framework update

我有一个 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() 方法停止工作了,这一直很有效。现在它抛出异常 "The algorithm group '' is invalid"。如果我删除 .net framework 4.6.2,它会再次运行。

link中的示例代码将重现该错误,它会加密成功然后解密失败。

我使用的是 A3 证书,pendrive 令牌。有人遇到过这个问题吗?在 .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

.Net 4.6.2 中的一些运行时更改会影响 EncrtyptedXml - 请参阅 https://msdn.microsoft.com/en-us/library/mt670901(v=vs.110).aspx#Anchor_5

我 运行 今天遇到了一些非常相似的东西,结果证明是 .NET 4.6.2 中的一个错误: https://github.com/Microsoft/dotnet/issues/341

针对这个问题,有两种解决方法:

1) Upgrading the OS to Windows Server 2012R2 or newer, 2) loading the user profile.

我自己无法重现问题 - 我没有 "pendrive token" 我怀疑是问题所在 - 所以这是猜测。 Windows - the "old" one and the "new generation" one, known as CNG 中有两代密码 API。 现在,如果您查看堆栈跟踪中途出现的 source code for the CngLightup type,特别是 DetectRsaCngSupport 方法,您会发现 .NET 框架尽可能尝试使用新一代 API .我的猜测是 "pendrive token" 设备不支持新的 API。您可以通过强制使用旧的 API 来验证这一点。不幸的是,似乎没有 public 配置标志来控制它,因此您必须求助于基于反射的 hack。例如,您可以在程序的开头放置这样的内容,以便在尝试解密操作之前运行一次:

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

请注意,它非常 hacky,不是线程安全的,省略了错误处理等。如果您确认 CNG 使用是问题所在,您可以要求 "pendrive token" 供应商提供驱动程序使用压缩天然气。或者你可以接受上面的 hack,为更安全而重写。