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

thi*_*321 4 c# cryptography

我有这个代码,用于解密文件,但如果我运行它,它会在using语句结束时抛出CryptographicException(要解密的数据的长度无效) 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");
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

我的加密方法:

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");
            }
        }
Run Code Online (Sandbox Code Playgroud)

Wol*_*yrd 14

您的代码存在一些问题:

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

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

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

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

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

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

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

这是一套经过修改的方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

和:

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);
}
Run Code Online (Sandbox Code Playgroud)