The "Internal: Could not decrypt data: Padding is invalid and cannot be removed." error occurs when a different encryption key is used to try and decrypt the encrypted data.
PKCS7 padding is a generalization of PKCS5 padding (also known as standard padding). PKCS7 padding works by appending N bytes with the value of chr(N) , where N is the number of bytes required to make the final block of data the same size as the block size.
The padded value is 32 bytes in length, which is two AES blocks. This padded string is encrypted in CBC mode, and the resulting cipher text will also be 32 bytes in length.
Rijndael/AES is a block cypher. It encrypts data in 128 bit (16 character) blocks. Cryptographic padding is used to make sure that the last block of the message is always the correct size.
Your decryption method is expecting whatever its default padding is, and is not finding it. As @NetSquirrel says, you need to explicitly set the padding for both encryption and decryption. Unless you have a reason to do otherwise, use PKCS#7 padding.
Make sure that the keys you use to encrypt and decrypt are the same. The padding method even if not explicitly set should still allow for proper decryption/encryption (if not set they will be the same). However if you for some reason are using a different set of keys for decryption than used for encryption you will get this error:
Padding is invalid and cannot be removed
If you are using some algorithm to dynamically generate keys that will not work. They need to be the same for both encryption and decryption. One common way is to have the caller provide the keys in the constructor of the encryption methods class, to prevent the encryption/decryption process having any hand in creation of these items. It focuses on the task at hand (encrypting and decrypting data) and requires the iv
and key
to be supplied by the caller.
For the benefit of people searching, it may be worth checking the input being decrypted. In my case, the info being sent for decryption was (wrongly) going in as an empty string. It resulted in the padding error.
This may relate to rossum's answer, but thought it worth mentioning.
If the same key and initialization vector are used for encoding and decoding, this issue does not come from data decoding but from data encoding.
After you called Write method on a CryptoStream object, you must ALWAYS call FlushFinalBlock method before Close method.
MSDN documentation on CryptoStream.FlushFinalBlock method says:
"Calling the Close method will call FlushFinalBlock ..."
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs.110).aspx
This is wrong. Calling Close method just closes the CryptoStream and the output Stream.
If you do not call FlushFinalBlock before Close after you wrote data to be encrypted, when decrypting data, a call to Read or CopyTo method on your CryptoStream object will raise a CryptographicException exception (message: "Padding is invalid and cannot be removed").
This is probably true for all encryption algorithms derived from SymmetricAlgorithm (Aes, DES, RC2, Rijndael, TripleDES), although I just verified that for AesManaged and a MemoryStream as output Stream.
So, if you receive this CryptographicException exception on decryption, read your output Stream Length property value after you wrote your data to be encrypted, then call FlushFinalBlock and read its value again. If it has changed, you know that calling FlushFinalBlock is NOT optional.
And you do not need to perform any padding programmatically, or choose another Padding property value. Padding is FlushFinalBlock method job.
.........
Additional remark for Kevin:
Yes, CryptoStream calls FlushFinalBlock before calling Close, but it is too late: when CryptoStream Close method is called, the output stream is also closed.
If your output stream is a MemoryStream, you cannot read its data after it is closed. So you need to call FlushFinalBlock on your CryptoStream before using the encrypted data written on the MemoryStream.
If your output stream is a FileStream, things are worse because writing is buffered. The consequence is last written bytes may not be written to the file if you close the output stream before calling Flush on FileStream. So before calling Close on CryptoStream you first need to call FlushFinalBlock on your CryptoStream then call Flush on your FileStream.
A serval times of fighting, I finally solved the problem.
(Note: I use standard AES as symmetric algorithm. This answer may not suitable
for everyone.)
RijndaelManaged
class to AESManaged
one. KeySize
of algorithm class, left them default.Here is a list you want to check which argument you might have missed:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With