我刚开始使用C#中的密码学,试图先加密然后解密文件。但是在解密过程中 私有静态字节[]解密(byte [] inputBuffer) , 在 byte [] outputBuffer = transform.TransformFinalBlock(inputBuffer,0,inputBuffer.Length); 我收到以下异常: System.Security.Cryptography.CryptographicException:“无效的数据”。 但是为什么呢?
这是读取文件的功能:
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;
}
答案 0 :(得分:2)
您的加密代码产生的输出缓冲区比输入缓冲区大。如果您一次独立加密4096字节,它将产生4104字节的输出 1 。如果您希望继续独立地加密文件的每个块,则需要更改解密代码,以使其在成块工作时使用4104字节缓冲区。
尽管理想情况下,这不是“分别加密每个块”的要求。在这种情况下,请一次创建transform
对象 ,而不是每次循环都创建一次。然后使用Transform
而不是TransformFinalBlock
,直到您知道文件的末尾为止(请注意,它们返回的内容非常不同)。
您还忽略了bytesRead
,它告诉您您的缓冲区有多少被有用数据填充。您还需要使用它,并且不要使最后的加密回合x
个字节(即文件的最后一个字节)和{em> previous 块的bufferSize - x
个字节。文件中的数据。
我可能想创建一个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
将得到类似的简化。
答案 1 :(得分:0)
我遇到了同样的问题,然后我创建了一个用于加密/解密的自定义函数,并且使用该函数还支持大文件,因为我们正在逐块读取和写入文件。有一个 EncryptMode 就是你想要的这种方法,比如如果你想加密然后发送 _mode 作为 _mode.ENCRYPT,如果你想解密然后发送 _mode 作为 _mode.DECRYPT。
私有枚举 EncryptMode { ENCRYPT, DECRYPT };
public void encryptDecryptChunkByChunk(string _inputPath, string _outputPath, string _encryptionKey, EncryptMode _mode, string _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();
}