4

I have an AES Cryptography wrapper and unit tests that has been working for over a year. Now after installing VS 2012 (or maybe an update to .net Framework 4) the unit tests do not pass. The streamreader block was throwing a CryptographicException when I passed in a bad pass but is not throwing a ArgumentNullException.

The code is up at. https://github.com/jnaus/Cryptography


Here is the unit test that now does not work. (BadSaltTest has the same problem)

[TestMethod]
[ExpectedException(typeof(CryptographicException),
  "Bad password was inappropriately allowed")]
public void BadPasswordTest()
{
    var cipherText = EncryptString();
    var decryptedText = AESCryptography.DecryptStringAES
        (cipherText,"A bad password", salt);
}

Test Result: Test method CryptographyTest.AESTest.BadPasswordTest threw exception System.ArgumentNullException, but exception System.Security.Cryptography.CryptographicException was expected. Exception message: System.ArgumentNullException: Value cannot be null. Parameter name: inputBuffer

Decrypt code.

public static string DecryptStringAES(string cipherText, 
    string password, byte[] salt)
{   
    RijndaelManaged aesAlg = null;
    string plaintext = null;

    try 
    {
        // generate the key from the shared secret and the salt
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt);

        // Create a RijndaelManaged object
        // with the specified key and IV.
        aesAlg = new RijndaelManaged();
        aesAlg.Key = key.GetBytes(aesAlg.KeySize/8);
        aesAlg.IV = key.GetBytes(aesAlg.BlockSize/8);

        // Create a decrytor to perform the stream transform.
        ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, 
            aesAlg.IV);
        // Create the streams used for decryption.                
        byte[] bytes = Convert.FromBase64String(cipherText);

        using (MemoryStream msDecrypt = new MemoryStream(bytes)) 
        {
            using (CryptoStream csDecrypt = 
                new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) 
            {
                //StreamReader now gives ArgumentNullException
                using (StreamReader srDecrypt = new StreamReader(csDecrypt)) 
                {
                    // Read the decrypted bytes from the decrypting stream
                    // and place them in a string.
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
    }
    finally 
    {
        // Clear the RijndaelManaged object.
        if (aesAlg != null)
        {
            aesAlg.Clear();
        }
    }
    return plaintext;
}
Dave Zych
  • 21,581
  • 7
  • 51
  • 66
Jimmy James
  • 381
  • 1
  • 3
  • 6
  • 1
    This is confusing. Do you mean "The streamreader block was throwing a CryptographicException when I passed in a bad pass but is *now* throwing a ArgumentNullException." And are you positive it is the StreamReader block throwing the exception. – paparazzo Sep 21 '12 at 19:30
  • I think you should have a good look at that `EncryptString()` method in your test case and see if that returns `null`... – Maarten Bodewes Sep 21 '12 at 20:42
  • Yes my unit test BadPasswordTest is expecting a CryptographicException which until just recently was working. Not it is returning ArgumentNullException. See the test result above. – Jimmy James Sep 21 '12 at 21:17
  • EncryptString() is used in all the Unit tests and it is working fine. – Jimmy James Sep 21 '12 at 21:23
  • I'll add that this has been working and not changed since 6/11/2011. See the Github https://github.com/jnaus/Cryptography – Jimmy James Sep 21 '12 at 21:26

2 Answers2

2

After searching around a bit more, this indeed does appear to be a bug as confimred by Microsoft (see Microsoft Connect). Personally not a big fan of the suggested workaround as it really shouldn't be needed but it will do in the mean time I suppose.

Adam Goss
  • 1,017
  • 3
  • 14
  • 22
1

The code you posted above worked for me (I had to write some code to create an encrypted string to pass). Compiled and run in VS2012 using .Net Framework 4.

The encryption code I used was:

    private static string EncryptStringAES(string plainText, string password, byte[] salt)
    {
        RijndaelManaged aesAlg = null;
        string cypherText = null;

        try
        {
            // generate the key from the shared secret and the salt
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, salt);

            // Create a RijndaelManaged object
            // with the specified key and IV.
            aesAlg = new RijndaelManaged();
            aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
            aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);

            // Create an encryptor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            // Create the streams used for encryption.                
            byte[] bytes = new UTF8Encoding().GetBytes(plainText);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    csEncrypt.Write(bytes, 0, bytes.Length);
                    csEncrypt.FlushFinalBlock();
                    cypherText = Convert.ToBase64String(msEncrypt.ToArray());
                }
            }
        }
        finally
        {
            // Clear the RijndaelManaged object.
            if (aesAlg != null)
            {
                aesAlg.Clear();
            }
        }
        return cypherText;
    }

Used the following to make the method calls:

        byte[] salt =  new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
        string test = DecryptStringAES(EncryptStringAES("This is a test", "Test", salt), "Test", salt);

Resulting string (Test) contained "This is a test".

Kevin
  • 31
  • 1
  • My code works it is just 2 of the unit test do not work as they did earlier this year. – Jimmy James Sep 21 '12 at 21:10
  • I ran the above code from within a unit test (one I already had set up), just added the two calling lines and did a Debug Selected Tests from the Test Explorer. – Kevin Sep 21 '12 at 21:15
  • The ArgumentNullException being where you indicate it is, is saying that csDecrypt is null at that point. You need to step through your code and determine why the CryptoStream is failing to get created. – Kevin Sep 21 '12 at 21:23
  • Ok, not sure why your test was working before, but I did some digging... When I pass in a bad password to the decrypt method, there are two exceptions being thrown (nested) the inner exception is an ArgumentNullException that is happening when the CryptoStream gets disposed (inputBuffer is null in the call to System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock). The outer exception is a CryptographicException "Padding is invalid and cannot be removed." thrown by System.Security.Cryptography.RijndaelManagedTransform.DecryptData. – Kevin Sep 21 '12 at 21:56
  • Yes that is what I am seeing also, the 2 exceptions. Some machines are returning the CryptException and some machines are returning the Null, so there seems to be some .NET Frame work change. All the machines that get the NULLException now have VS 2012 on them and it looks like there was a patch to .net 4. – Jimmy James Sep 21 '12 at 22:00
  • I've been having the same issue. Using .NET reflector I've stepped through the code (there is a lot to go through) but eventually I got to the point where it throws the expected CryptographicException. From there it goes through a series of clean up code through a dispose method at which point it clears out some buffers and sets it to null. From here this then result in the ArgumentNullException that get's thrown and is ruining our unit tests. I'm guessing as you say, there must be some strange framework change that has caused this. – Adam Goss Dec 05 '12 at 23:28