Padding is invalid and cannot be removed?

2019-01-02 20:25发布

问题:

I have looked online for what this exception means in relation to my program but can't seem to find a solution or the reason why it's happening to my specific program. I have been using the example provided my msdn for encrypting and decrypting an XmlDocument using the Rijndael algorithm. The encryption works fine but when I try to decrypt, I get the following exception:

Padding is invalid and cannot be removed

Can anyone tell me what I can do to solve this issue? My code below is where I get the key and other data. If the cryptoMode is false, it will call the decrypt method, which is where the exception occurs:

public void Cryptography(XmlDocument doc, bool cryptographyMode)
{
    RijndaelManaged key = null;
    try
    {
    // Create a new Rijndael key.
    key = new RijndaelManaged();
    const string passwordBytes = "Password1234"; //password here 

    byte[] saltBytes = Encoding.UTF8.GetBytes("SaltBytes");
    Rfc2898DeriveBytes p = new Rfc2898DeriveBytes(passwordBytes, saltBytes);
    // sizes are devided by 8 because [ 1 byte = 8 bits ] 
    key.IV = p.GetBytes(key.BlockSize/8);
    key.Key = p.GetBytes(key.KeySize/8);

    if (cryptographyMode)
    {
        Ecrypt(doc, "Content", key);
    }
    else
    {
        Decrypt(doc, key);
    }

    }
    catch (Exception ex)
    {
    MessageBox.Show(ex.Message);
    }
    finally
    {
    // Clear the key.
    if (key != null)
    {
        key.Clear();
    }
    }

}

private void Decrypt(XmlDocument doc, SymmetricAlgorithm alg)
{
    // Check the arguments.  
    if (doc == null)
    throw new ArgumentNullException("Doc");
    if (alg == null)
    throw new ArgumentNullException("alg");

    // Find the EncryptedData element in the XmlDocument.
    XmlElement encryptedElement = doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;

    // If the EncryptedData element was not found, throw an exception.
    if (encryptedElement == null)
    {
    throw new XmlException("The EncryptedData element was not found.");
    }


    // Create an EncryptedData object and populate it.
    EncryptedData edElement = new EncryptedData();
    edElement.LoadXml(encryptedElement);

    // Create a new EncryptedXml object.
    EncryptedXml exml = new EncryptedXml();


    // Decrypt the element using the symmetric key.
    byte[] rgbOutput = exml.DecryptData(edElement, alg); <----  I GET THE EXCEPTION HERE
    // Replace the encryptedData element with the plaintext XML element.
    exml.ReplaceData(encryptedElement, rgbOutput);

}

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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.)

  1. Change the algorithm class. Replace the RijndaelManaged class to AESManaged one.
  2. Do not explicit set the KeySize of algorithm class, left them default.
    (This is the very important step. I think there is a bug in KeySize property.)

Here is a list you want to check which argument you might have missed:

  • Key
    (byte array, length must be exactly one of 16, 24, 32 byte for different key size.)
  • IV
    (byte array, 16 bytes)
  • CipherMode
    (One of CBC, CFB, CTS, ECB, OFB)
  • PaddingMode
    (One of ANSIX923, ISO10126, None, PKCS7, Zeros)


回答5:

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.



回答6:

My issue was that the encrypt's passPhrase didn't match the decrypt's passPhrase... so it threw this error .. a little misleading.



回答7:

Another scenario, again for the benefit of people searching.

For me this error occurred during the Dispose() method which masked a previous error unrelated to encryption.

Once the other component was fixed, this exception went away.



回答8:

I encountered this padding error when i would manually edit the encrypted strings in the file (using notepad) because i wanted to test how decryption function will behave if my encrypted content was altered manually.

The solution for me was to place a

        try
            decryption stuff....
        catch
             inform decryption will not be carried out.
        end try

Like i said my padding error was because i was manually typing over the decrypted text using notepad. May be my answer may guide you to your solution.



回答9:

The solution that fixed mine was that I had inadvertently applied different keys to Encryption and Decryption methods.



回答10:

I had the same error. In my case it was because I have stored the encrypted data in a SQL Database. The table the data is stored in, has a binary(1000) data type. When retreiving the data from the database, it would decrypt these 1000 bytes, while there where actually 400 bytes. So removing the trailing zero's (600) from the result it fixed the problem.



回答11:

I came across this error while attempting to pass an un-encrypted file path to the Decrypt method.The solution was to check if the passed file is encrypted first before attempting to decrypt

if (Sec.IsFileEncrypted(e.File.FullName))
{
    var stream = Sec.Decrypt(e.File.FullName);
} 
else
{
    // non-encrypted scenario  
}


标签: