11

I have an old function written in 2013 that decrypt xml that was encrypted by another program.

The code is realy simple

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

    }

It worked like a charm until recently that some of our clients started to upgrade their framework to 4.6.2, so the method DecryptDocument() stopped working. Now it throws an exception "The algorithm group '' is invalid". If I remove .net framework 4.6.2 it works again.

The sample code in this link will reproduce the error, it will encrypt successfully then fail to decrypt.

I'm using A3 certificates, pendrive token. Anyone have faced this problem? there is any work around in .net 4.6.2?

Edit 1:

Stacktrace:

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

Leonardo Xavier
  • 443
  • 3
  • 16
  • 1
    Do you have a full stacktrace? – Maarten Bodewes May 30 '17 at 00:14
  • Did clients to a complete rebuild? Have client make copy of bin folder in project. Then delete bin folder and recompile. I suspect error is due to dependencies in compiler. The compiler doesn't have any dependencies to Net Version so when new Net is installed a full recompile is required. The compiler will not automatically do a full compile. – jdweng May 30 '17 at 05:01
  • @jdweng It fails even on my development machine, I started a new project, pasted the sample code from this [link](https://msdn.microsoft.com/en-us/library/ms148633(v=vs.110).aspx). It failed to decrypt. – Leonardo Xavier May 30 '17 at 12:10
  • I would start by comparing .proj files (which are ASCII) to make sure no settings changed. VS 2013 change a lot of default settings. VS2013 changes default for character encoding from UTF8 to Unicode which may explain the issue. I would think the issue is with VS not Net Libraries. Just changing Net Libraries a completely rebuilding project should work. Occasionally Microsoft changes default settings when Net is upgraded, but that is unusual. – jdweng May 30 '17 at 12:42
  • I'm fairly confident that this is a .net framework problem. The program is compiled for .NET 4.0. If I copy to a virtual machine newly installed with .NET 4.6.2, the program will not work. If on this same machine I remove the .net framework and install 4.5.2 the program will work correctly. I tried recompiling the program to target the .net framework 4.6.2, I made a clean rebuild, but it still does not work. Old versions of the program, compiled in 2013, also stop working in .NET 4.6.2. – Leonardo Xavier May 30 '17 at 12:59
  • The driver for your certificate's private key reports that it has an algorithm group of the empty string. That's not expected. If you can break on the exception and see what values for Algorithm, and Provider(.Name) are, that'd be useful for filing an issue at https://github.com/dotnet/corefx/ – bartonjs May 31 '17 at 00:27
  • Try debugging during encryption by creating a variable with the value of `cert.GetRSAPrivateKey()`. In there, tell us what the respective values of `.Key.Algorithm`, `.Key.AlgorithmGroup` and `.Key.Provider` are. – silkfire Jun 01 '17 at 22:59
  • cert.GetRSAPrivateKey() also throws the same exception `The algorithm group '' is invalid. Parameter name: algorithmGroup` stacktrace: `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)` – Leonardo Xavier Jun 02 '17 at 13:28
  • It only occurs with A3 certs? – cineam mispelt Jun 05 '17 at 10:00
  • I suppose so, I created a pfx self signed certificate and it worked without any error – Leonardo Xavier Jun 05 '17 at 12:43

3 Answers3

2

There are some runtime changes in .Net 4.6.2 that affect EncrtyptedXml - see https://msdn.microsoft.com/en-us/library/mt670901(v=vs.110).aspx#Anchor_5

ZippyZippedUp
  • 458
  • 5
  • 14
  • Thanks for the info, but this link does not say anything about not being able to use A3 certificates for decryption, with the @silkfire comment I discovered that not even an instance of RSAPrivateKey I can get. I do not think this is a problem with the token manufacturer, since several clients using different tokens are reporting the same problem. In addition, it does not indicate how to solve the problem. – Leonardo Xavier Jun 02 '17 at 13:42
2

I cannot reproduce the problem myself - I don't have the "pendrive token" which I suspect is the problem - so this is guesswork. There are two generations of cryptographic APIs in Windows - the "old" one and the "new generation" one, known as CNG. Now, if you look at the source code for the CngLightup type that appears midway through your stack trace, specifically the DetectRsaCngSupport method, you'll see that .NET framework tries to use the new generation API if possible. My guess is that the "pendrive token" device does not support the new API. You can verify this by forcing the use of the old API. Unfortunately, there does not seem to be a public configuration flag that controls this, so you must resort to reflection-based hacks. For example, you can put something like this at the beginning of your program, so that it runs once, before you try the decrypting operation:

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

Do note that it is extremely hacky, not thread-safe, error handling is omitted etc. If you verify that the CNG usage is the problem, you can then ask the "pendrive token" supplier to provide drivers that work with CNG. Or you can live with the hack above, rewritten for more safety.

cynic
  • 5,305
  • 1
  • 24
  • 40
  • Thank you very much, I tested and it worked. I can dive deeper into the problem now that I know what exactly was going wrong. And this hack will buy me some time to find a better solution, if there is any. – Leonardo Xavier Jun 08 '17 at 12:10
0

I ran into something very similar today that turned out to be a bug in .NET 4.6.2: https://github.com/Microsoft/dotnet/issues/341

According to this issue, there are two workarounds:

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

Sam Rueby
  • 5,914
  • 6
  • 36
  • 52
  • 1
    Thank you for your suggestion. I Installed a virtual machine with Windows Server 2012R2, I applied all windows updates and it still does not work with .net framework 4.6.2. I'm using a desktop application, so configuring IIS to load user profile doesn't fit. – Leonardo Xavier Jun 07 '17 at 20:08