47

I'm trying to get simple encryption/decryption working with AesManaged, but I keep getting an exception when trying to close the decryption stream. The string here gets encrypted and decrypted correctly, and then I get the CryptographicException "Padding was invalid and cannot be removed" after Console.WriteLine prints the correct string.

Any ideas?

MemoryStream ms = new MemoryStream(); byte[] rawPlaintext = Encoding.Unicode.GetBytes("This is annoying!"); using (Aes aes = new AesManaged()) { aes.Padding = PaddingMode.PKCS7; aes.Key = new byte[128/8]; aes.IV = new byte[128/8]; using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(rawPlaintext, 0, rawPlaintext.Length); cs.FlushFinalBlock(); } ms = new MemoryStream(ms.GetBuffer()); using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read)) { byte[] rawData = new byte[rawPlaintext.Length]; int len = cs.Read(rawData, 0, rawPlaintext.Length); string s = Encoding.Unicode.GetString(rawData); Console.WriteLine(s); } } 

6 Answers 6

65

The trick is to use MemoryStream.ToArray(). I also changed your code so that it uses the CryptoStream to Write, in both encrypting and decrypting. And you don't need to call CryptoStream.FlushFinalBlock() explicitly, because you have it in a using() statement, and that flush will happen on Dispose(). The following works for me.

byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!"); using (Aes aes = new AesManaged()) { aes.Padding = PaddingMode.PKCS7; aes.KeySize = 128; // in bits aes.Key = new byte[128/8]; // 16 bytes for 128 bit encryption aes.IV = new byte[128/8]; // AES needs a 16-byte IV // Should set Key and IV here. Good approach: derive them from // a password via Cryptography.Rfc2898DeriveBytes byte[] cipherText= null; byte[] plainText= null; using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(rawPlaintext, 0, rawPlaintext.Length); } cipherText= ms.ToArray(); } using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(cipherText, 0, cipherText.Length); } plainText = ms.ToArray(); } string s = System.Text.Encoding.Unicode.GetString(plainText); Console.WriteLine(s); } 

Also, I guess you know you will want to explicitly set the Mode of the AesManaged instance, and use System.Security.Cryptography.Rfc2898DeriveBytes to derive the Key and IV from a password and salt.

see also:
- AesManaged

Sign up to request clarification or add additional context in comments.

4 Comments

I had the same problem, but using RijndaelManaged (also symmetric) and had no idea what was happening. Turns out that MemoryStream.GetBuffer() was getting an unflushed version of the data, and most of the final blocks of data were null, which was messing with my padding. MemoryStream.ToArray() gets the real array. Many thanks for this solution!
This is the best/smallest implementation I have seen so far.
Good call on Dispose. I was calling ms.ToArray() before disposing CryptoStream. Moving that line outside of the using fixed it for me.
oh my days, a million thanks @cheeso ! Writing to crypto stream while decrypting and memoryStream.ToArray().... thanks a million once again! That ends 10 hours of hair pulling!
33

This exception can be caused by a mismatch of any one of a number of encryption parameters.

I used the Security.Cryptography.Debug interface to trace all parameters used in the encrypt/decrypt methods.

Finally I found out that my problem was that I set the KeySize property after setting the Key causing the class to regenerate a random key and not using the key that I was initially set up.

3 Comments

My problem was also setting KeySize after setting the key, Thanks!
+1 Thank you so much, I'd vote you up 100 times if I could. I have spent over a day trying to figure out why I couldn't decrypt properly and it turned out I was setting the key size after the key in the code.
Is Security.Cryptography.Debug still up to date? It seems to have had no changes since 2010
7

For whats its worth, I'll document what I faced. I was trying to read the encryptor memory stream before the CryptoStream was closed. I was naive and I wasted a day debugging it.

 public static byte[] Encrypt(byte[] buffer, byte[] sessionKey, out byte[] iv) { byte[] encrypted; iv = null; using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 }) { aesAlg.Key = sessionKey; iv = aesAlg.IV; ICryptoTransform encryptor = aesAlg.CreateEncryptor(sessionKey, iv); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { csEncrypt.Write(buffer, 0, buffer.Length); //This was not closing the cryptostream and only worked if I called FlushFinalBlock() //encrypted = msEncrypt.ToArray(); } encrypted = msEncrypt.ToArray(); return encrypted; } } } 

Moving the encryptor memory stream read after the cypto stream was closed solved the problem. As Cheeso mentioned. You don't need to call the FlushFinalBlock() if you're using the using block.

1 Comment

WOW MAN, AMAZING!!!, you saved my day, about seven hours trying to figure it out... Really I can't thank you enough
2

byte[] rawData = new byte[rawPlaintext.Length];

You need to read the length of the buffer, that probably includes the necessary padding (IIRC, been a few years).

Comments

2

Nobody answered, that actually MemoryStream.GetBuffer returns the allocated buffer, not the real data in this buffer. In this case it returns 256-byte buffer, while it contains only 32 bytes of encrypted data.

Comments

0

As others have mentioned, this error can occur if the key/iv is not correctly initialized for decryption. In my case I need to copy key and iv from some larger buffer. Here's what I did wrong:

Does not work: (Padding is invalid and cannot be removed)

aes.Key = new byte[keySize]; Buffer.BlockCopy(someBuffer, keyOffset, aes.Key, 0, keySize); aes.IV = new byte[ivSize]; Buffer.BlockCopy(someBuffer, ivOffset, aes.IV, 0, ivSize); 

Works:

var key = new byte[keySize]; Buffer.BlockCopy(someBuffer, keyOffset, key, 0, keySize); aes.Key = key; var iv = new byte[ivSize]; Buffer.BlockCopy(someBuffer, ivOffset, iv, 0, ivSize); aes.IV = iv; 

The OP did not make this mistake, but this might be helpful for others seeing the same error.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.