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

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

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

我的加密方式:

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

最佳答案

您的代码存在一些问题:

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

  2. 您使用 Encoding.UTF8 从您的文件中加载字节,您需要读取原始字节,您可以使用以下代替:

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

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

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

  5. 当您就地覆盖时,您可以使用 Create 与文件交互。如果您知道该文件已经存在(因为您正在替换它),您应该使用 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);
}

和:

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

关于C# CryptographicException 要解密的数据长度无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25892173/

相关文章:

c# - 返回带有模型和查询字符串的 View

c# - 将 int 替换为 double 时的 Visual Studio 长编译

C# 在流中使用关键字

c# - 如何在 AWS RDS 上配置分布式事务?

c# - 基于 FIPS 186-2 的伪随机数生成器

node.js - 如何在 Node.js 中重现 Bash HMAC 加密

c# - .NET - 数字的字母数字表示

node.js - EVP_DecryptFinal_ex :bad decrypt when using Node. js

java - 循环群生成器

javascript - 即使使用 webcrypto-shim,crypto.subtle 也不存在