C # CryptographicException data length to decrypt is not valid

I have this code which is for decrypting a file, but if I run it, it throws a CryptographicException (data length is invalid to decrypt) 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 anyone know why this is the case or how I can fix this? (I don't know if this comes from my encryption method, but I have another program that uses the same thing to encrypt strings and that it works.)

My encryption 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");
            }
        }

      

+4


source to share


3 answers


There are several problems with the code:

  • You are using Zeroes fill mode in Encrypt and None in decryption. They must match

  • You are loading bytes from your file using Encoding.UTF8, you need to read the raw bytes, you can do that using the following instead:

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

  • You call cryptoStream.FlushFinalBlock();

    when you only use one iteration of the stream. You don't need this call in Decrypt if you are only doing one block iteration.

  • You read the original text from your file in UTF8 and then write it as ASCII. You should either change the destination of the result in the decryption to use UTF8, or (preferably) change both to use raw bytes.

  • You use Create to interact with files when overwriting in place. If you know the file already exists (how are you replacing it) then you should use truncation or better yet, just call File.WriteAllBytes.

  • Your decryption ruined everything. It looks like you are binding to nodes using byte search. You should just use the raw bytes from the CryptoStream and not try to use UTF8

Here's a revised set of methods:



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);
}

      

+14


source


In my case, this happened because I was decrypting a value that was never encrypted.

My values ​​were stored in the database without encryption. But when I put the encryption and decryption routine into my code and ran my program for the first time, it was actually trying to decrypt a value that was never encrypted, and so there was a problem.



Simply clearing the existing values ​​from the database for initial run solved the problem. If you do not want to lose data even during the first run, you should write a separate routine to encrypt the existing values.

+2


source


Most likely your problem is with cipherTextBytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());

You cannot use UTF8 to encode arbitrary binary data, you will most likely need to fix both ends of the encryption of the final decryption. You must either use cipherTextBytes = File.ReadAllBytes(path)

, or if you are forced to use strings, you must first encode the bytes to a valid string usingConvert.ToBase64String()

+1


source







All Articles