panman
panman

Reputation: 75

Decryption error Length of data to decrypt is invalid

I am performing independent encrypt-decrypt (1st app performs enc 2nd decrypts) While decryption I either get "Padding invalid" or "Length of data to decrypt is invalid" error.Any help is appreciated thanks My encryption code:

static void EncryptFile(string file, string password)
    {
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

        RijndaelManaged AES = new RijndaelManaged();
        AES.KeySize = AES.LegalKeySizes[0].MaxSize;
        AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
        AES.Padding = PaddingMode.Zeros;

        using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000)) 
        {
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            AES.Mode = CipherMode.CFB;
        }
        using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Create))
        {

            fsCrypt.Write(salt, 0, salt.Length);
        }

        int bytesToRead = 128 * 1024 * 1024; // 128MB 
        byte[] buffer = new byte[bytesToRead]; // create the array that will be used encrypted
        long fileOffset = 0;
        int read = 0;
        bool allRead = false;

        while (!allRead)
        {
            using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
            {
                fs.Seek(fileOffset, SeekOrigin.Begin); // continue reading from where we were...
                read = fs.Read(buffer, 0, bytesToRead); // read the next chunk
            }

            if (read == 0)
                allRead = true;
            else
                fileOffset += read;

            using (FileStream fsCrypt = new FileStream(file + ".ecc", FileMode.Open)) // automatically dispose fsCrypt
            {
                using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {

                    fsCrypt.Seek(fileOffset, SeekOrigin.End);
                    cs.FlushFinalBlock();
                    cs.Write(buffer, 0, read);

                }
            }
        }

    }

and My decryption code:

public void DecryptFile(string file,  string password)
    {
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
        byte[] salt = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

        RijndaelManaged AES = new RijndaelManaged();
        AES.KeySize = AES.LegalKeySizes[0].MaxSize;
        AES.BlockSize = AES.LegalBlockSizes[0].MaxSize;
        AES.Padding = PaddingMode.Zeros;

        using (var key = new Rfc2898DeriveBytes(passwordBytes, salt, 1000))
        {
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);
            AES.Mode = CipherMode.CFB;
        }


        string extension = System.IO.Path.GetExtension(file);
        string result = file.Substring(0, file.Length - extension.Length);
        using (FileStream destination = new FileStream(result, FileMode.CreateNew, FileAccess.Write, FileShare.None))
        {
            using (CryptoStream cryptoStream = new CryptoStream(destination, AES.CreateDecryptor(), CryptoStreamMode.Write))
            {
                try
                {
                    using (FileStream source = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        source.CopyTo(cryptoStream);
                    }
                }
                catch (CryptographicException exception)
                {
                    if (exception.Message == "Padding is invalid and cannot be removed.")
                        throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
                    else
                        throw;
                }
            }
        }
    }

Upvotes: 1

Views: 1804

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93978

The following calls are executed in the wrong order:

cs.FlushFinalBlock();

and

cs.Write(buffer, 0, read);

FlushFinalBlock should always come last (it will be automatically called when the stream is closed though, so it should be OK if you don't close the underlying stream first). FlushFinalBlock should certainly never be called in a (while) loop.

The buffer handling is not correct: the streams should not be closed and opened all the time. Instead a block of bytes should be read, then written to the crypto stream. The using statements should be outside the while loop.

For CFB mode PaddingMode.PKCS7 should be set. Padding is not required at all for CFB. Unfortunately .NET seems to have a buggy implementation that does require padding to be used in combination to the streams.

Upvotes: 2

Related Questions