Search code examples
c#windowsencryptionwindows-server-2012rijndaelmanaged

Rijndael cryptography not working on Windows Server 2012


I have a Windows Application (x64) that has been working fine on Winodws 7, 8 and now 10. Today we failed at running the program under a Windows 2012 Server. When we looked at the event log, we found an error originating from System.Security.Cryptography.RijndaelManaged..ctor() (unfortunately the log did not give us the complete path).

I have used the Rijndael algorithm to for encrypting sensitive data in my program. The first thing the program does is to retrieve the encrypted config file and decrypt it in order to get all the settings. And this is where my program does not start.

This is the decrypt method in my program:

public static string Decrypt(string cipherText, string passPhrase)
{
    byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
    using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
    {
        byte[] keyBytes = password.GetBytes(keysize / 8);
        using (RijndaelManaged symmetricKey = new RijndaelManaged())
        {
            symmetricKey.Mode = CipherMode.CBC;
            using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
            {
                using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                        return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                    }
                }
            }
        }
    }
}

And this is the error message I get in the log:

Application: Postbag.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.InvalidOperationException at System.Security.Cryptography.RijndaelManaged..ctor() at Common.StringCipher.Decrypt(System.String, System.String) at Common.Conf..cctor() Exception Info: System.TypeInitializationException at Common.Conf.get_DataProvider() at Postbag.FormMain..ctor() at Postbag.Program.Main()

The new server also has the same versions of the .Net framework.


Solution

  • The RijndaelManaged clases are not FIPS compliant and your server seems to have the Security Policy System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing set.

    In the Knowledgebase artical "System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing" security setting effects in Windows XP and in later versions of Windows it says:

    Microsoft .NET Framework applications such as Microsoft ASP.NET only allow for using algorithm implementations that are certified by NIST to be FIPS 140 compliant. Specifically, the only cryptographic algorithm classes that can be instantiated are those that implement FIPS-compliant algorithms. The names of these classes end in "CryptoServiceProvider" or "Cng." Any attempt to create an instance of other cryptographic algorithm classes, such as classes with names ending in "Managed," cause an InvalidOperationException exception to occur

    So either disable the security policy (from the SecPol.msc tool) or use a FIPS compliant implementation. Unfortunately Rijndael doesn't have such implementation so you might want to see if AesCng or AesCryptoServiceProvider matches your needs because AES is the formal implementation of what started as Rijndael. Based on the blog Is RijndaelManaged class FIPS compliant? from Prateek Kr Dubey I conclude that data that is encrypted with RijdaelManaged can be decrypted with AesCng or AesCryptoServiceProvider.

    To be complete I created an Encrypt method with the RijnDaelManaged class and adapted your code example on this line:

    using (RijndaelManaged symmetricKey = new RijndaelManaged())
    

    to read

    using (var symmetricKey = new AesCryptoServiceProvider()) // or new AesCng()
    

    and was indeed able to decrypt the string.