C#CryptographicException要解密的数据长度无效

时间:2014-09-17 13:37:18

标签: c# cryptography

我有这个代码用于解密文件,但是如果我运行它,它会在using语句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");
            }
        }
    }

有人知道这是为什么或我如何解决它? (我不知道它是否来自我的加密方法,但我有另一个程序使用完全相同的东西来加密字符串,并且确实有效。)

我的加密方法:

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

3 个答案:

答案 0 :(得分:14)

您的代码存在一些问题:

  1. 在Decrypt中使用加密中的零填充模式和无填充模式。这些需要匹配

  2. 您使用Encoding.UTF8从文件加载字节,您需要读取原始字节,您可以使用以下代码来执行此操作:

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

  3. 仅使用流的单次迭代时调用cryptoStream.FlushFinalBlock();。如果您只进行一次块迭代,则在Decrypt中不需要此调用。

  4. 您在UTF8中读取文件中的原始文本,然后以ASCII格式将其写回。您应该在decrypt中更改结果分配以使用UTF8或(最好)更改两者以使用原始字节。

  5. 在就地覆盖时,使用“创建”与文件​​进行交互。如果您知道该文件已经存在(当您替换它时),您应该使用truncate或更好的方法,只需调用File.WriteAllBytes。

  6. 你的解密是各种搞砸了。看起来你正在将自己绑在字节检索的结上。你应该只使用CryptoStream中的原始字节而不是尝试使用UTF8

  7. 以下是一套经过修改的方法:

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

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

答案 1 :(得分:2)

在我的情况下,它发生了,因为我正在解密一个从未加密过的值。

我将我的值保存在数据库中而没有加密。但是当我在我的代码中引入加密和解密例程并且第一次执行我的程序时,实际上它试图解密一个从未加密过的值,因此问题就出现了。

只需从数据库中清除初始运行中的现有值即可解决问题。如果您不想在第一次运行期间丢失数据,那么您应该编写一个单独的例程来加密现有值。

答案 2 :(得分:1)

您的问题很可能来自cipherTextBytes = Encoding.UTF8.GetBytes(reader.ReadToEnd());

您无法使用UTF8对任意二进制数据进行编码,您可能需要修复加密端解密端。您必须使用cipherTextBytes = File.ReadAllBytes(path)或者如果您被迫使用字符串,则必须首先使用Convert.ToBase64String()将字节编码为有效字符串