Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# CryptographicException length of the data to decrypt is invalid

I have this code which is meant to decrypt a file, but if I run it, it throws a CryptographicException (length of the data to decrypt is invalid) at the end of the using statement using (CryptoStream ...) { ... }

public static void DecryptFile(string path, string key, string saltkey, string ivkey)
        {
            try
            {
                byte[] cipherTextBytes;

                using (StreamReader reader = new StreamReader(path)) cipherTextBytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());

                byte[] keyBytes = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(saltkey)).GetBytes(256 / 8);

                RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };
                ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(ivkey));

                byte[] plainTextBytes;

                using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        plainTextBytes = new byte[Encoding.UTF8.GetByteCount((new StreamReader(cryptoStream)).ReadToEnd())];

                        cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                        //plainTextBytes = memoryStream.ToArray();

                        cryptoStream.FlushFinalBlock();
                    }
                }

                string result = Encoding.ASCII.GetString(plainTextBytes, 0, plainTextBytes.Length).TrimEnd("\0".ToCharArray());

                using (FileStream writer = new FileStream(path, FileMode.Create)) writer.Write(Encoding.ASCII.GetBytes(result), 0, Encoding.ASCII.GetBytes(result).Length);

                MessageBox.Show("Decrypt succesfull");
            }

            catch (Exception ex)
            {
                MessageBox.Show("An error while decrypting the file:\n\n" + ex, "Error");
            }
        }
    }

Does anybody know why this is or how I can fix it? (I don't know if it comes from my encrypting method, but I have another program which uses the exact same thing to encrypt strings and that one does work.)

My encrypting method:

public static void EncryptFile(string path, string key, string saltkey, string ivkey)
        {
            try
            {
                byte[] TextBytes;

                using (StreamReader reader = new StreamReader(path)) TextBytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());

                byte[] KeyBytes = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(saltkey)).GetBytes(256 / 8);

                RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
                ICryptoTransform encryptor = symmetricKey.CreateEncryptor(KeyBytes, Encoding.ASCII.GetBytes(ivkey));

                byte[] CipherTextBytes;

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        cs.Write(TextBytes, 0, TextBytes.Length);

                        cs.FlushFinalBlock();

                        CipherTextBytes = ms.ToArray();
                    }
                }

                using (FileStream writer = new FileStream(path, FileMode.Create)) writer.Write(CipherTextBytes, 0, CipherTextBytes.Length);

                MessageBox.Show("Encrypt succesfull");
            }

            catch (Exception ex)
            {
                MessageBox.Show("An error while encrypting the file:\n\n" + ex, "Error");
            }
        }
like image 701
thijmen321 Avatar asked Nov 30 '22 18:11

thijmen321


2 Answers

There are a few issues with your code:

  1. You use a padding mode of Zeroes in Encrypt and None in Decrypt. These need to match

  2. You load the bytes from your file using Encoding.UTF8, you need to read the raw bytes, you can do this by using the following instead:

    byte[] cipherTextBytes = File.ReadAllBytes(path);

  3. You call cryptoStream.FlushFinalBlock(); when only using a single iteration of a stream. You don't need this call in Decrypt if you are only doing a single block iteration.

  4. You read the original text from your file in UTF8 and then write it back as ASCII. You should either change the result assignment in decrypt to use UTF8 or (preferably) change both to use raw bytes.

  5. You use Create to interact with the files when you are overwriting in-place. If you know the file already exists (as you are replacing it) you should use truncate or better yet just call File.WriteAllBytes.

  6. Your decrypt is all kinds of messed up. It looks like you're tying yourself into knots over byte retrieval. You should just use the raw bytes out of the CryptoStream and not try using UTF8

Here's a revised set of methods for you:

public static void DecryptFile(string path, string key, string saltkey, string ivkey)
{
    byte[] cipherTextBytes = File.ReadAllBytes(path);

    byte[] keyBytes = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(saltkey)).GetBytes(256 / 8);

    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CFB, Padding = PaddingMode.PKCS7 };
    ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(ivkey));

    byte[] plainTextBytes;

    const int chunkSize = 64;

    using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
    using (MemoryStream dataOut = new MemoryStream())
    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
    using (var decryptedData = new BinaryReader(cryptoStream))
    {
        byte[] buffer = new byte[chunkSize];
        int count;
        while ((count = decryptedData.Read(buffer, 0, buffer.Length)) != 0)
        dataOut.Write(buffer, 0, count);

        plainTextBytes = dataOut.ToArray();
    }     

    File.WriteAllBytes(path, plainTextBytes);
}

and:

public static void EncryptFile(string path, string key, string saltkey, string ivkey)
{
    byte[] TextBytes = File.ReadAllBytes(path);

    byte[] KeyBytes = new Rfc2898DeriveBytes(key, Encoding.ASCII.GetBytes(saltkey)).GetBytes(256 / 8);

    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CFB, Padding = PaddingMode.PKCS7 };
    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(KeyBytes, Encoding.ASCII.GetBytes(ivkey));

    byte[] CipherTextBytes;

    using (MemoryStream ms = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
    {
        cs.Write(TextBytes, 0, TextBytes.Length);
        cs.FlushFinalBlock();         

        CipherTextBytes = ms.ToArray();
    }

    File.WriteAllBytes(path, CipherTextBytes);
}
like image 169
Wolfwyrd Avatar answered Dec 06 '22 20:12

Wolfwyrd


Most likely your problem comes from cipherTextBytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());

You can't use UTF8 to encode arbitrary binary data, you will likely need to fix both your encrypting end decrypting end. You either must use cipherTextBytes = File.ReadAllBytes(path) or if you are forced to use strings you must first encode the bytes to a valid string using Convert.ToBase64String()

like image 41
Scott Chamberlain Avatar answered Dec 06 '22 20:12

Scott Chamberlain