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

本文关键字:无效 数据 解密 C#CryptographicException | 更新日期: 2023-09-27 18:22:08

我有这个代码,它是用来解密文件的,但如果我运行它,它会在using语句using (CryptoStream ...) { ... } 的末尾抛出CryptographicException(要解密的数据长度无效)

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

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

您的代码有几个问题:

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

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

    byte[]cipherTextBytes=文件.ReadAllBytes(路径);

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

和:

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

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

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

在我的案例中,这是因为我正在解密一个从未加密的值。

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

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