要解密的数据的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");
}
}
您的代码有几个问题:
-
在"加密"中使用零填充模式,在"解密"中使用无填充模式。这些需要匹配
-
您使用Encoding.UTF8从文件中加载字节,您需要读取原始字节,您可以使用以下方法:
byte[]cipherTextBytes=文件.ReadAllBytes(路径);
-
当只使用流的单个迭代时,可以调用
cryptoStream.FlushFinalBlock();
。如果您只执行单个块迭代,则不需要在Decrypt中进行此调用。 -
您可以用UTF8从文件中读取原始文本,然后将其写回ASCII。您应该将decrypt中的结果分配更改为使用UTF8,或者(最好)将两者都更改为使用原始字节。
-
使用"创建"可以在覆盖到位时与文件进行交互。如果你知道文件已经存在(当你替换它时),你应该使用truncate,或者更好的方法是调用file.WriteAllBytes.
-
你的解密搞砸了。看起来你在字节检索上陷入了困境。您应该只使用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()
将字节编码为有效字符串
在我的案例中,这是因为我正在解密一个从未加密的值。
我的值在没有加密的情况下保存在数据库中。但当我在代码中引入加密和解密例程并第一次执行程序时,它实际上是在试图解密一个从未加密过的值,因此出现了问题。
只需在初始运行时从数据库中清除现有值就可以解决问题。如果您不想在第一次运行时丢失数据,那么您应该编写一个单独的例程来加密现有值。