dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.06k stars 4.69k forks source link

Cryptographic cryptoTransform.TransformFinalBlock() Throws Exception "Padding is invalid and cannot be removed" when data is passed in chunks #103470

Closed kogoel closed 2 months ago

kogoel commented 3 months ago

Description

Problem Statement: While trying to decrypt the encrypted bytes in chunks, getting exception in cryptoTransform.TransformFinalBlock() as "Padding is invalid and cannot be removed"

Encryption: Have added some custom code to prepend 4 bytes on initial block only for some information, no other blocks have this 4 byte header information.

Decryption: When passing the data in chunks (buffer of 4096 as Memory Stream or FileStream) I am removing the top 4 bytes, then passing the remaining data as below to tranform block. _cryptoTransform.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);

while after all the chunks are decrypted the last bock of 4 bytes are passed to TransformFinalBlock() as below: _cryptoTransform.TransformFinalBlock(inputBuffer,0,0); Throws Padding exception .

However when data is passed as memory stream or file stream without chunking the last 4 bytes are decrypted as expected and there is no exception.

Note: Also linking an existing https://github.com/dotnet/runtime/issues/83381

Reproduction Steps

Encryption is done similarly just 4 byte header is prepended in the encrypted bytes in our custom code. Decryption Code block:

private static void Decryption(string fileIn, string fileOut, NaeRijndaelKey key)
        {
            char[] _fileIn = fileIn.ToCharArray();
            char[] _fileOut = fileOut.ToCharArray();

            using (FileStream fsIn = new FileStream(string.Concat(_fileIn), FileMode.Open, FileAccess.Read))
            {
                using (FileStream fsOut = new FileStream(string.Concat(_fileOut), FileMode.OpenOrCreate, FileAccess.Write))
                {
                    key.Padding = PaddingMode.PKCS7;
                    ICryptoTransform decryptor = key.CreateDecryptor();
                    using (CryptoStream cs = new CryptoStream(fsOut, decryptor, CryptoStreamMode.Write))
                    {
                        long totaldata = 0;
                        try
                        {

                            byte[] buffer = null;
                            int bytesRead;
                            do
                            {
                                buffer = new byte[bufferLen];
                                // read a chunk of data from the input file
                                bytesRead = fsIn.Read(buffer, 0, bufferLen);

                                // encrypt it
                                cs.Write(buffer, 0, bytesRead);
                                totaldata = totaldata + bufferLen;
                            }
                            while (bytesRead != 0);
                            Array.Clear(buffer, 0, buffer.Length);
                            buffer = null;
                            decryptor.Dispose();
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("total" + totaldata);
                            throw new Exception("Error occurred while decrypting buffer: " + e.Message);
                        }
                    }
                    fsOut.Close();
                }
                fsIn.Close();
            }
        }

Expected behavior

There should not be exception. It should process the encrypted as when data is not passed in chunks.

Actual behavior

Getting exception: Cryptographic error "Padding is invalid and cannot be removed"

Regression?

No response

Known Workarounds

No response

Configuration

Sample is in .Net 6.0, Library is on .netstandard 2.1

Other information

https://github.com/dotnet/runtime/issues/83381

vcsjones commented 3 months ago

I don't think there is enough information here to fully diagnose the problem. Particularly, NaeRijndaelKey appears to be a custom implementation of SymmetricAlgorithm (or one of its derivatives). bufferLen is also an undefined variable.

A couple of suggestions.

  1. If you can put together code that is runnable that will greatly speed up diagnosing the issue.
  2. ".Net 6.0" Can you try in .NET 8? Some fixes have been made to CryptoStream after .NET 6 was released, such as #82148.
dotnet-policy-service[bot] commented 3 months ago

This issue has been automatically marked no-recent-activity because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove no-recent-activity.

dotnet-policy-service[bot] commented 2 months ago

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.