1

It seems that THIS question is related, but it's not.
In my case the exception "padding is invalid and cannot be removed" occurs when decrypting, in the related question is it when encrypting

The first question people ask is: what have you tried? I've tried a lot. So even after removing all superfluous text, my description is quite long. Sorry for that.

My conclusion is that the exception 'padding is invalid and cannot be removed' is thrown within CryptoSteam.FlushFinalBlock, which is called by CryptoStream.Dispose(). This happens if nothing has been read from the Stream.

Reference source CryptoStream.FlushFinalBlock

If I read all data or at least one byte during the decryption process everything works fine.

If I read nothing, I get a CryptoGraphicException. Padding is invalid and cannot be removed.

I tried the following:

  • Below a complete encrypt / decrypt cycle. Works fine, no exception, no need to change default padding, no FlushFinalBlock needed. The read data equals the original data
  • If I only read one byte: no exception either, no need to change default padding, no FlushFinalBlock needed. A proper Dispose() takes care of this
  • If I don't read anything I get the mentioned exception
  • An extra FlushFinalBlock before Dispose does not help

The code below shows a complete correctly working encrypt / decrypt Test procedure. The decrypted bytes equal the original bytes:

Data:

byte[] key;
byte[] iv;
byte[] testData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] encryptedData;
byte[] decryptedData;

Encryption of the data:

using (Stream testStream = new MemoryStream(testData))
{
    using (RijndaelManaged rijndael = new RijndaelManaged())
    {   // Generate and remember keys:
        rijndael.GenerateKey();
        rijndael.GenerateIV();
        key = rijndael.Key;
        iv = rijndael.IV;

        using (var encryptor = rijndael.CreateEncryptor())
        {
            using (var cryptoStream = new CryptoStream(testStream, encryptor,
                   CryptoStreamMode.Read))
            {   // read all bytes from the cryptoStream and put in a EncryptedData
                using (BinaryReader reader = new BinaryReader(cryptoStream))
                {
                    encryptedData = reader.ReadBytes(10000);
                    // expect no bytes anymore
                }
            }
        }
    }
}

All TestBytes are encrypted in encryptedData. key and iv are known

Decrypt the data

using (Stream encryptedStream = new MemoryStream(encryptedData))
{
    using (var rijnDael = new RijndaelManaged())
    {
        rijnDael.Key = key;
        rijnDael.IV = iv;
        using (var decryptor = rijnDael.CreateDecryptor())
        {
            using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
                   CryptoStreamMode.Read))
            {
                using (BinaryReader reader = new BinaryReader(decryptedStream))
                {
                    decryptedData = reader.ReadBytes(1000);
                    // expect no bytes anymore
                }
            }
        }
    }
}

// Check that the decrypted data equals the original data:
Debug.Assert(testData.SequenceEqual(decryptedData));

This works fine. If I read only one decrypted byte, there is no exception:

using (BinaryReader reader = new BinaryReader(decryptedStream))
{
    byte b = reader.ReadByte();
}

However, If I read nothing the exception occurs:

using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
       CryptoStreamMode.Read))
{
    using (BinaryReader reader = new BinaryReader(decryptedStream))
    {
    } // exception during Dispose()
}

One of the answers in the related question mentioned at the beginning included a FlushFinalBlock. This does not help, as expected, because the CrypteStream.Dispose already calls this

using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
       CryptoStreamMode.Read))
{
    using (BinaryReader reader = new BinaryReader(decryptedStream))
    {
        if (!decryptedStream.HasFlushedFinalBlock)
        { 
            decryptedStream.FlushFinalBlock();
            // even though it hasn't flushed the final bloc
            // I get the same Exception during Flush
         }
    } 
}

So now we know that the Exception occurs because of CryptoStream.FlushFinalBlock, which is also done in the CryptoStream.Dispose()

The problem has nothing to do with the binary reader. If I read directly one byte then there is no exception, without reading anything I get the exception during the Dispose of the CryptoStream

using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
       CryptoStreamMode.Read))
{
    int b = decryptedStream.ReadByte();
} // exception during Dispose()

So what should I do to prevent the exception? Read one dummy byte? Seems a bit silly, isn't it?

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • 1
    In the linked question "when I try to **decrypt**, I get the following exception:" (My emphasis). So what makes you think the linked question is about encryption? Also, if you'll read up a little on encryption and padding, you'll realise that it doesn't make *sense* to get such an error during encryption. – Damien_The_Unbeliever Jun 07 '18 at 10:12
  • oops.my fault. Repaired – Harald Coppoolse Jun 07 '18 at 10:40

0 Answers0