解密异常——要解密的数据长度无效
本文关键字:解密 无效 异常 数据 | 更新日期: 2023-09-27 17:50:45
我在一个c#应用程序工作。在文件中存储数据有常用的方法。这些方法加密数据并将其存储在文件系统中。当我们需要数据时,ReadData方法解密数据并返回纯文本。
如果文本的大小很小,这段代码在正常情况下可以正常工作。但是对于下面给出的示例文本,解密代码抛出异常-要解密的数据长度无效。
异常发生在
行 // close the CryptoStream
x_cryptostream.Close();
我尝试了不同的方法,但没有运气。有人能帮帮忙吗?
为什么我要加密已经加密的数据-我只是试图使用大型应用程序的通用方法存储在文件中。常用的方法storedata(key,data)
和readdata(key)
做加密/解密我无法避免。
public static byte[] Decrypt(byte[] ciphertext, string Key, string IV)
{
byte[] k = Encoding.Default.GetBytes(Key);
byte[] iv = Encoding.Default.GetBytes(IV);
// create the encryption algorithm
SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
x_alg.Padding = PaddingMode.PKCS7;
// create an ICryptoTransform that can be used to decrypt data
ICryptoTransform x_decryptor = x_alg.CreateDecryptor(k, iv);
// create the memory stream
MemoryStream x_memory_stream = new MemoryStream();
// create the CryptoStream that ties together the MemoryStream and the
// ICryptostream
CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
x_decryptor, CryptoStreamMode.Write);
// write the ciphertext out to the cryptostream
x_cryptostream.Write(ciphertext, 0, ciphertext.Length);
// close the CryptoStream
x_cryptostream.Close();
// get the plaintext from the MemoryStream
byte[] x_plaintext = x_memory_stream.ToArray();
下面是加密方法的代码。
public static byte[] Encrypt(string strplain, string Key, string IV)
{
byte[] k = Encoding.Default.GetBytes(Key);
byte[] iv = Encoding.Default.GetBytes(IV);
byte[] plaintext = Encoding.Default.GetBytes(strplain);
// create the encryption algorithm
SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");
x_alg.Padding = PaddingMode.PKCS7;
// create an ICryptoTransform that can be used to encrypt data
ICryptoTransform x_encryptor = x_alg.CreateEncryptor(k, iv);
// create the memory stream
MemoryStream x_memory_stream = new MemoryStream();
// create the CryptoStream that ties together the MemoryStream and
// the ICryptostream
CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
x_encryptor, CryptoStreamMode.Write);
// write the plaintext out to the cryptostream
x_cryptostream.Write(plaintext, 0, plaintext.Length);
// close the CryptoStream
x_cryptostream.Close();
// get the ciphertext from the MemoryStream
byte[] x_ciphertext = x_memory_stream.ToArray();
// close memory stream
x_memory_stream.Close();
// convert from array to string
string cipher_Tx = Encoding.Default.GetString(x_ciphertext,
0, x_ciphertext.Length);
x_encryptor.Dispose();
x_alg.Clear();
byte[] cipher = Encoding.Default.GetBytes(cipher_Tx);
return cipher;
}
你的问题是string cipher_Tx = Encoding.Default.GetString(x_ciphertext, 0, x_ciphertext.Length);
。
x_ciphertext
不是文本的有效字节表示,它有许多不可呈现的字符,当您做byte[]
到string
转换时,您正在丢失信息。正确的方法是使用字符串格式,该格式被设计为使用Convert.ToBase64String(byte[])
和Convert.FromBase64String(string)
来表示二进制数据。
string cipher_Tx = Convert.ToBase64String(x_ciphertext)
x_encryptor.Dispose();
x_alg.Clear();
byte[] cipher = Convert.FromBase64String(cipher_Tx)
话虽这么说,还有很多其他的"奇怪"。关于你的代码的一些事情,例如你不使用using
语句,你真的应该使用。而且,整个字符串和返回的转换是完全没有必要的,只返回x_ciphertext
。代码也可能存在其他问题(如Key
和IV
的字符串来自哪里)和许多其他最佳实践(如您应该生成随机IV并将其写入输出,密钥应该使用密钥派生函数而不是直接从用户文本生成),但我在发现字符串转换问题后停止检查。
只要用于解密的密钥和iv与用于加密的密钥和iv匹配,上面的代码就可以工作。试试这个:
byte[] test = new byte[1000000];
for (int i = 0; i < 256; i++)
{
test[i] = (byte)i;
}
var ciphertext = Encrypt(Encoding.Default.GetString(test), "0000000000000000", "0000000000000000");
byte[] check = Decrypt(ciphertext, "0000000000000000", "0000000000000000");
for (int i = 0; i < 256; i++)
{
Debug.Assert(check[i] == (byte)i, "round trip");
}
正如你所看到的,一百万个字节对你的代码进行加密和解密就足够了,所以我认为这与数据大小没有任何关系。
但是,像这样改变IV:
byte[] check = Decrypt(ciphertext, "0000000000000000", "000000000000000X"); // note X
和Debug。Assert将触发——解密将不匹配。但是,x_cryptostream.Close()成功。
接下来,试着像这样改变键:
byte[] check = Decrypt(ciphertext, "000000000000000X", "0000000000000000"); // note X
现在,x_cryptostream.Close()将失败并返回一个CryptographicException,可能是"Padding是无效的,不能被删除"。
损坏密钥会导致解密失败,x_cryptostream.Close()也会失败。
我认为问题出在你保存和稍后恢复密钥字节上。
BTW:希望您使用的是密钥的完整二进制范围,而不是仅基于ASCII字符,否则您就没有真正的强密钥。