Search code examples
c#.netcryptographyaes

Why RijndaelManaged raises the following exception: Padding is invalid and cannot be removed?


In a .NET4/C# application, I have the following encryption methods:

        public static byte[] Encrypt(byte[] data, byte[] key, out byte[] iv)
        {
            byte[] encryptedData;
            using (var aes = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = KEY_SIZE,
                BlockSize = BLOCK_SIZE
            })
            {
                aes.GenerateIV();
                var encryptor = aes.CreateEncryptor(key, aes.IV);

                using (var msEncrypt = new MemoryStream())
                {
                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        csEncrypt.Write(data, 0, data.Length);
                        csEncrypt.FlushFinalBlock();
                    }
                    encryptedData = msEncrypt.ToArray();
                }
                iv = new byte[aes.IV.Length];
                aes.IV.CopyTo(iv, 0);
            }
            return encryptedData;
        }

        public static byte[] Encrypt(byte[] data, string sKey, out byte[] iv)
        {
            return Encrypt(data, Encoding.UTF8.GetBytes(sKey), out iv);
        }

and the following decryption methods:

        public static byte[] Decrypt(byte[] encryptedData, byte[] key, byte[] iv)
        {
            byte[] data;
            using (var aes = new RijndaelManaged()
            {
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC,
                KeySize = KEY_SIZE,
                BlockSize = BLOCK_SIZE
            })
            {
                var decryptor = aes.CreateDecryptor(key, iv);
                using (var msData = new MemoryStream())
                {
                    using (var csEncrypt = new CryptoStream(msData, decryptor, CryptoStreamMode.Read))
                    {
                        csEncrypt.Read(encryptedData, 0, encryptedData.Length);
                    }
                    data = msData.ToArray();
                }
            }
            return data;
        }

        public static byte[] Decrypt(byte[] encryptedData, string sKey, byte[] iv)
        {
            return Decrypt(encryptedData, Encoding.UTF8.GetBytes(sKey), iv);
        }

I wrote this unit test.

        [TestMethod]
        public void TestEncryptDecryptBytes()
        {
            Random rnd = new Random(666);
            string key = "ABCDEFGHABCDEFGHABCDEFGHABCDEFGH";

            //Run 100 times
            for (int i = 0; i < 100; i++)
            {
                byte[] buf = new byte[rnd.Next(100, 1024)];
                rnd.NextBytes(buf);
                byte[] iv;
                var enc = Crypto.Encrypt(buf, key, out iv);
                var dec = Crypto.Decrypt(enc, key, iv);
                Assert.AreEqual(buf.Length, dec.Length);
                for (int j = 0; j < buf.Length; j++)
                {
                    Assert.AreEqual(buf[j], dec[j]);
                }
            }
        }

And I get the following exception while decrypting the encrypted data.

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.

Can't figure out what is wrong. I am pretty sure the key and the IV are the same during encryption and decryption. Block size and key size are also the same. Any help is appreciated.


Solution

  • You are decrypting the data incorrectly. Try this:

    public static byte[] Decrypt(byte[] encryptedData, byte[] key, byte[] iv)
    {
        byte[] data;
        using (var aes = new RijndaelManaged()
        {
            Padding = PaddingMode.PKCS7,
            Mode = CipherMode.CBC,
            KeySize = KEY_SIZE,
            BlockSize = BLOCK_SIZE
        })
        {
            var decryptor = aes.CreateDecryptor(key, iv);
    
            using (var encStream = new MemoryStream(encryptedData))
            {
                using (var csDecrypt = new CryptoStream(encStream, decryptor, CryptoStreamMode.Read))
                {
                    using (var msData = new MemoryStream())
                    {
                        csDecrypt.CopyTo(msData);
                        data = msData.ToArray();
                    }
                }
            }
        }
        return data;
    }