gpt4 book ai didi

c# - 对大文件使用 Rijndael 加密

转载 作者:太空狗 更新时间:2023-10-29 20:18:38 25 4
gpt4 key购买 nike

我现在需要安全地加密/解密一个长度为 n 的文件,最好使用 Rijndael,但绝对是 256 位加密。

我以前玩过加密,并且非常愉快地加密/解密字符串和字节数组。但是,因为我不知道文件的大小(而且有问题的文件可能非常大(~2.5gb)是非常可行的)我不能只将它们加载到字节数组中并在其中加密/解密它们像我以前一样的单一界限。

因此,在谷歌上进行了一些阅读之后,我知道答案是分块加密和解密文件,因此我生成了以下代码:

private static void Enc(string decryptedFileName, string encryptedFileName)
{
FileStream fsOutput = File.OpenWrite(encryptedFileName);
FileStream fsInput = File.OpenRead(decryptedFileName);

byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
fsOutput.Write(IVBytes, 0, 16);

RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC};
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordDB.GetBytes(256 / 8), IVBytes);
CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write);

for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
fsInput.Read(chunkData, 0, chunkSize);
cryptoStream.Write(chunkData, 0, chunkData.Length);
}
cryptoStream.Close();
fsInput.Close();
fsInput.Dispose();
cryptoStream.Dispose();
}

private static void Dec(string encryptedFileName, string decryptedFileName)
{
FileStream fsInput = File.OpenRead(encryptedFileName);
FileStream fsOutput = File.OpenWrite(decryptedFileName);

byte[] buffer = new byte[8];
fsInput.Read(buffer, 0, 8);

long fileLength = BitConverter.ToInt64(buffer, 0);

byte[] IVBytes = new byte[16];
fsInput.Read(IVBytes, 0, 16);

RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC };
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordDB.GetBytes(256 / 8), IVBytes);
CryptoStream cryptoStream = new CryptoStream(fsOutput,decryptor,CryptoStreamMode.Write);

for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
fsInput.Read(chunkData, 0, chunkSize);
cryptoStream.Write(chunkData, 0, chunkData.Length);
}
cryptoStream.Close();
cryptoStream.Dispose();
fsInput.Close();
fsInput.Dispose();
}

这一切对我来说都“看起来”不错,但遗憾的是看起来似乎是骗人的!

加密工作没有错误,但在解密过程中,“cryptoStream.Close()”方法抛出以下异常:

System.Security.Cryptography.CryptographicException was unhandled Message="Padding is invalid and cannot be removed."
Source="mscorlib" StackTrace: at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.CryptoStream.FlushFinalBlock() at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) at System.IO.Stream.Close()

似乎未加密的文件大小与预期的文件大小不匹配(范围从大约 8 个字节到大约 60 个字节)

我通过更改 RijndaelManaged 对象创建行以包含填充类型来“修复”异常,如下所示:

RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.None };

但是文件大小仍然不匹配,可以预见,新的未加密文件是胡说八道!

我承认我现在在加密/解密方面超出了我的舒适区,这可能是一个菜鸟错误 - 但我无法发现它!

如能提供解决此问题的任何帮助,我们将不胜感激!

最佳答案

问题是我正在使用:

passwordDB.GetBytes(256 / 8)

在加密和解密方法中的 RijndaelManaged 对象的构造函数中,我没有在尝试解密之前重新初始化 passwordDB 对象。

解决方案是简单地将 passwordDB 对象的构造包含在 Enc 和 Dec 方法的第一行中,如下所示:

        private static void Enc(string decryptedFileName, string encryptedFileName)
{
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

using (FileStream fsOutput = File.OpenWrite(encryptedFileName))
{
using(FileStream fsInput = File.OpenRead(decryptedFileName))
{
byte[] IVBytes = Encoding.ASCII.GetBytes("1234567890123456");

fsOutput.Write(BitConverter.GetBytes(fsInput.Length), 0, 8);
fsOutput.Write(IVBytes, 0, 16);

RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.ANSIX923};
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(passwordBytes, IVBytes);

using (CryptoStream cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write))
{
for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
{
if (bytesRead != 16)
{
for (int x = bytesRead - 1; x < chunkSize; x++)
{
chunkData[x] = 0;
}
}
cryptoStream.Write(chunkData, 0, chunkSize);
}
}
cryptoStream.FlushFinalBlock();
}
}
}
}

private static void Dec(string encryptedFileName, string decryptedFileName)
{
PasswordDeriveBytes passwordDB = new PasswordDeriveBytes("ThisIsMyPassword", Encoding.ASCII.GetBytes("thisIsMysalt!"), "MD5", 2);
byte[] passwordBytes = passwordDB.GetBytes(128 / 8);

using (FileStream fsInput = File.OpenRead(encryptedFileName))
{
using (FileStream fsOutput = File.OpenWrite(decryptedFileName))
{
byte[] buffer = new byte[8];
fsInput.Read(buffer, 0, 8);

long fileLength = BitConverter.ToInt64(buffer, 0);

byte[] IVBytes = new byte[16];
fsInput.Read(IVBytes, 0, 16);


RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC,Padding=PaddingMode.ANSIX923};
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(passwordBytes, IVBytes);

using (CryptoStream cryptoStream = new CryptoStream(fsOutput, decryptor, CryptoStreamMode.Write))
{
for (long i = 0; i < fsInput.Length; i += chunkSize)
{
byte[] chunkData = new byte[chunkSize];
int bytesRead = 0;
while ((bytesRead = fsInput.Read(chunkData, 0, chunkSize)) > 0)
{
cryptoStream.Write(chunkData, 0, bytesRead);
}
}
}
}
}
}

知道这一定是一个小学生的错误:P

关于c# - 对大文件使用 Rijndael 加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3351285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com