为什么我在解密这个字节数组时得到 System.Security.Cryptography.CryptographicException
Why do I get a System.Security.Cryptography.CryptographicException during decrypting this byte array
我刚开始使用 C# 中的密码学,并尝试先加密然后解密文件。但是在解密过程中,在函数中
private static byte[] Decrypt(byte[] inputBuffer)
, 在
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
我收到以下异常:
System.Security.Cryptography.CryptographicException:"Invalid data"。
但这是为什么呢?
这是读取文件的函数:
private static void DecryptFile()
{
byte[] buffer = new byte[4096];
byte[] decryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\Encrypted.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\Decrypt.mp3"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
decryptionBuffer = Decrypt(buffer);
outputStream .Write(decryptionBuffer, 0, decryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
这是解密文件、密钥和初始化向量的函数:
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Decrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateDecryptor(key, iv);
//here the exception is triggered
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
文件是这样加密的:
private static void EncryptFile()
{
byte[] buffer = new byte[4096];
byte[] enryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\Test.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\Encrypted.txt"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
encryptionBuffer = Encrypt(buffer);
outputStream .Write(encryptionBuffer, 0, encryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
//Key and initialization vector are the same
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
您的加密代码产生比输入缓冲区更大的输出缓冲区。如果你一次独立加密4096字节,它会产生4104字节的输出1。如果您希望继续独立加密文件的每个块,则需要将解密代码更改为在分块工作时使用 4104 字节缓冲区。
理想情况下,这 "encrypt each block separately" 不是必需的。如果是这种情况,请创建 transform
对象 一次 ,而不是每次通过循环创建一次。并使用 Transform
而不是 TransformFinalBlock
直到你知道你已经到达文件的末尾(注意它们 return 但是非常不同的东西)。
您还忽略了 bytesRead
,它告诉您 您的缓冲区中有多少是有用的数据。你也需要使用它并且不要让你的最终加密轮是 x
很多字节,这是文件的最后字节和 bufferSize - x
字节 previous 文件中的数据块。
我可能会转而创建一个 CryptoStream
来包装您的 FileStream
对象之一,然后使用 Stream.CopyTo
或道德等价物来完成这项工作。让图书馆担心管理缓冲区、循环等。
最后,理想情况下,您认识到现在是 2019 年,编写使用 DES
进行加密的新代码还很不合适2
1这个程序,如果你在Console.ReadLine
行设置断点,c
包含4104字节:
using System;
using System.Security.Cryptography;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var b = new byte[4096];
var c = Encrypt(b);
Console.ReadLine();
}
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(
inputBuffer,
0,
inputBuffer.Length);
return outputBuffer;
}
}
2所以我的 EnryptFile
整体是:
private static void EncryptFile()
{
using (var inputStream = File.OpenRead(Environment.CurrentDirectory + "\Test.txt"))
using (var outputStream = File.Create(Environment.CurrentDirectory + "\Encrypted.txt"))
using (var aes = Aes.Create())
using (var cStream = new CryptoStream(
inputStream,
aes.CreateEncryptor(key, iv),
CryptoStreamMode.Read))
{
cStream.CopyTo(outputStream);
}
}
或者一个 async
变体,它使用 await cStream.CopyToAsync(outputStream);
作为最内层的语句。 DecryptFile
将得到类似的简化。
我遇到了同样的问题然后我为 encryption/decryption 创建了一个自定义函数并且使用这个函数还支持大文件 因为我们正在读写一个文件块按块。有一个 EncryptMode 就是你想要通过这种方法做什么,如果你想加密然后发送 _mode 作为 _mode.ENCRYPT 如果你想要解密然后发送 _mode 作为 _mode.DECRYPT.
私有枚举 EncryptMode {加密,解密};
public void encryptDecryptChunkByChunk(字符串_inputPath,字符串_outputPath,字符串_encryptionKey,EncryptMode _mode,字符串_initVector)
{
string _out = "";// output string
//_encryptionKey = MD5Hash (_encryptionKey);
_pwd = Encoding.UTF8.GetBytes(_encryptionKey);
_ivBytes = Encoding.UTF8.GetBytes(_initVector);
int len = _pwd.Length;
if (len > _key.Length)
{
len = _key.Length;
}
int ivLenth = _ivBytes.Length;
if (ivLenth > _iv.Length)
{
ivLenth = _iv.Length;
}
Array.Copy(_pwd, _key, len);
Array.Copy(_ivBytes, _iv, ivLenth);
_rcipher.Key = _key;
_rcipher.IV = _iv;
if (_mode.Equals(EncryptMode.ENCRYPT))
{
//encrypt
using (FileStream fs = new FileStream(_inputPath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputPath);
try
{
byte[] chunk;
chunk = br.ReadBytes(CHUNK_SIZE);
while (chunk.Length > 0)
{
var base641 = Convert.ToBase64String(chunk);
//DumpBytes(chunk, chunk.Length);
chunk = br.ReadBytes(CHUNK_SIZE);
var base64 = Convert.ToBase64String(chunk);
byte[] plainText = _rcipher.CreateEncryptor().TransformFinalBlock(_enc.GetBytes(base641), 0, base641.Length);
var bas64Encrypted = Convert.ToBase64String(plainText);
//fsCrypt.Write(bas64Encrypted);
file.WriteLine(bas64Encrypted);
}
file.Close();
}
catch (Exception ex)
{
file.Close();
}
}
}
}
if (_mode.Equals(EncryptMode.DECRYPT))
{
FileStream fsOut = new FileStream(_outputPath, FileMode.OpenOrCreate, FileAccess.Write);
try
{
foreach (string line in File.ReadLines(_inputPath))
{
// Process your line here....
var p = line;
var x2 = Convert.FromBase64String(p);
byte[] plainText = _rcipher.CreateDecryptor().TransformFinalBlock(x2, 0, x2.Length);
var y1 = _enc.GetString(plainText);
var y2 = Convert.FromBase64String(y1);
fsOut.Write(y2, 0, y2.Length);
}
fsOut.Close();
}
catch (Exception ex)
{
fsOut.Close();
}
}
_rcipher.Dispose();
}
我刚开始使用 C# 中的密码学,并尝试先加密然后解密文件。但是在解密过程中,在函数中 private static byte[] Decrypt(byte[] inputBuffer) , 在 byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length); 我收到以下异常: System.Security.Cryptography.CryptographicException:"Invalid data"。 但这是为什么呢?
这是读取文件的函数:
private static void DecryptFile()
{
byte[] buffer = new byte[4096];
byte[] decryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\Encrypted.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\Decrypt.mp3"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
decryptionBuffer = Decrypt(buffer);
outputStream .Write(decryptionBuffer, 0, decryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
这是解密文件、密钥和初始化向量的函数:
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Decrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateDecryptor(key, iv);
//here the exception is triggered
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
文件是这样加密的:
private static void EncryptFile()
{
byte[] buffer = new byte[4096];
byte[] enryptionBuffer = new byte[4096];
int bytesRead = 0;
using (FileStream inputStream = File.OpenRead(Environment.CurrentDirectory + "\Test.txt"))
{
using (FileStream outputStream = File.Create(Environment.CurrentDirectory + "\Encrypted.txt"))
{
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
encryptionBuffer = Encrypt(buffer);
outputStream .Write(encryptionBuffer, 0, encryptionBuffer.Length);
}
}
Console.WriteLine("Done.");
}
}
//Key and initialization vector are the same
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return outputBuffer;
}
您的加密代码产生比输入缓冲区更大的输出缓冲区。如果你一次独立加密4096字节,它会产生4104字节的输出1。如果您希望继续独立加密文件的每个块,则需要将解密代码更改为在分块工作时使用 4104 字节缓冲区。
理想情况下,这 "encrypt each block separately" 不是必需的。如果是这种情况,请创建 transform
对象 一次 ,而不是每次通过循环创建一次。并使用 Transform
而不是 TransformFinalBlock
直到你知道你已经到达文件的末尾(注意它们 return 但是非常不同的东西)。
您还忽略了 bytesRead
,它告诉您 您的缓冲区中有多少是有用的数据。你也需要使用它并且不要让你的最终加密轮是 x
很多字节,这是文件的最后字节和 bufferSize - x
字节 previous 文件中的数据块。
我可能会转而创建一个 CryptoStream
来包装您的 FileStream
对象之一,然后使用 Stream.CopyTo
或道德等价物来完成这项工作。让图书馆担心管理缓冲区、循环等。
最后,理想情况下,您认识到现在是 2019 年,编写使用 DES
进行加密的新代码还很不合适2
1这个程序,如果你在Console.ReadLine
行设置断点,c
包含4104字节:
using System;
using System.Security.Cryptography;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var b = new byte[4096];
var c = Encrypt(b);
Console.ReadLine();
}
private static byte[] key = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] iv = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
private static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm = DES.Create();
ICryptoTransform transform = algorithm.CreateEncryptor(key, iv);
byte[] outputBuffer = transform.TransformFinalBlock(
inputBuffer,
0,
inputBuffer.Length);
return outputBuffer;
}
}
2所以我的 EnryptFile
整体是:
private static void EncryptFile()
{
using (var inputStream = File.OpenRead(Environment.CurrentDirectory + "\Test.txt"))
using (var outputStream = File.Create(Environment.CurrentDirectory + "\Encrypted.txt"))
using (var aes = Aes.Create())
using (var cStream = new CryptoStream(
inputStream,
aes.CreateEncryptor(key, iv),
CryptoStreamMode.Read))
{
cStream.CopyTo(outputStream);
}
}
或者一个 async
变体,它使用 await cStream.CopyToAsync(outputStream);
作为最内层的语句。 DecryptFile
将得到类似的简化。
我遇到了同样的问题然后我为 encryption/decryption 创建了一个自定义函数并且使用这个函数还支持大文件 因为我们正在读写一个文件块按块。有一个 EncryptMode 就是你想要通过这种方法做什么,如果你想加密然后发送 _mode 作为 _mode.ENCRYPT 如果你想要解密然后发送 _mode 作为 _mode.DECRYPT.
私有枚举 EncryptMode {加密,解密};
public void encryptDecryptChunkByChunk(字符串_inputPath,字符串_outputPath,字符串_encryptionKey,EncryptMode _mode,字符串_initVector) {
string _out = "";// output string
//_encryptionKey = MD5Hash (_encryptionKey);
_pwd = Encoding.UTF8.GetBytes(_encryptionKey);
_ivBytes = Encoding.UTF8.GetBytes(_initVector);
int len = _pwd.Length;
if (len > _key.Length)
{
len = _key.Length;
}
int ivLenth = _ivBytes.Length;
if (ivLenth > _iv.Length)
{
ivLenth = _iv.Length;
}
Array.Copy(_pwd, _key, len);
Array.Copy(_ivBytes, _iv, ivLenth);
_rcipher.Key = _key;
_rcipher.IV = _iv;
if (_mode.Equals(EncryptMode.ENCRYPT))
{
//encrypt
using (FileStream fs = new FileStream(_inputPath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(_outputPath);
try
{
byte[] chunk;
chunk = br.ReadBytes(CHUNK_SIZE);
while (chunk.Length > 0)
{
var base641 = Convert.ToBase64String(chunk);
//DumpBytes(chunk, chunk.Length);
chunk = br.ReadBytes(CHUNK_SIZE);
var base64 = Convert.ToBase64String(chunk);
byte[] plainText = _rcipher.CreateEncryptor().TransformFinalBlock(_enc.GetBytes(base641), 0, base641.Length);
var bas64Encrypted = Convert.ToBase64String(plainText);
//fsCrypt.Write(bas64Encrypted);
file.WriteLine(bas64Encrypted);
}
file.Close();
}
catch (Exception ex)
{
file.Close();
}
}
}
}
if (_mode.Equals(EncryptMode.DECRYPT))
{
FileStream fsOut = new FileStream(_outputPath, FileMode.OpenOrCreate, FileAccess.Write);
try
{
foreach (string line in File.ReadLines(_inputPath))
{
// Process your line here....
var p = line;
var x2 = Convert.FromBase64String(p);
byte[] plainText = _rcipher.CreateDecryptor().TransformFinalBlock(x2, 0, x2.Length);
var y1 = _enc.GetString(plainText);
var y2 = Convert.FromBase64String(y1);
fsOut.Write(y2, 0, y2.Length);
}
fsOut.Close();
}
catch (Exception ex)
{
fsOut.Close();
}
}
_rcipher.Dispose();
}