处理和加密大文件时 C# 内存不足
C# Out of Memory while handling and encrypting large files
我正在尝试使用 AES 加密来加密一个大文件 (Camtasia.exe)。
现在由于某种原因我得到一个“内存不足”的异常。我对此很陌生,我不知道该如何解决。这是我的代码
我用这个来调用我的加密方法。
bytes = File.ReadAllBytes("Camtasia.exe");
Cryptography.Encryption.EncryptAES(System.Text.Encoding.Default.GetString(bytes), encryptionKey);
这是 AES 加密本身
public static string EncryptAES(string content, string password)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
using (SymmetricAlgorithm crypt = Aes.Create())
using (HashAlgorithm hash = MD5.Create())
using (MemoryStream memoryStream = new MemoryStream())
{
crypt.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// This is really only needed before you call CreateEncryptor the second time,
// since it starts out random. But it's here just to show it exists.
crypt.GenerateIV();
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
}
string base64IV = Convert.ToBase64String(crypt.IV);
string base64Ciphertext = Convert.ToBase64String(memoryStream.ToArray());
return base64IV + "!" + base64Ciphertext;
}
}
这是我在顶部调用函数“EncryptAES”时再次遇到的错误。如果有人能解释这是怎么发生的以及如何解决它,我会很高兴
https://imgur.com/xqcLsKW
您正在将整个 exe 读入内存,将其解释为 UTF-16 字符串 (??!),将其转回 UTF-8 字节,然后对其进行加密。这种转换 to/from 字符串的方法非常糟糕。可执行文件不是人类可读的字符串,即使它是人类可读的字符串,您对使用的编码也一头雾水。我想你可以放弃整个字符串。
您还将整个内容读入内存(实际上是多次,因为整个字符串的原因),这很浪费。您不需要这样做:您可以逐位加密它。为此,请使用 Stream。
像这样的东西应该可以工作(未经测试):至少它可以理解一般概念。我们设置了一系列流,让我们可以逐位读取输入文件中的数据,并将它们逐位写入输出文件。
// The file we're reading from
using var inputStream = File.OpenRead("Camtasia.exe");
// The file we're writing to
using var outputStream = File.OpenWrite("EncryptedFile.txt");
using var HashAlgorithm hash = MD5.Create();
using var aes = Aes.Create();
aes.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// Turn the IV into a base64 string, add "!", encode as UTF-8, and write to the file
string base64IV = Convert.ToBase64String(aes.IV) + "!";
byte[] base64IVBytes = Encoding.UTF8.GetBytes(base64IV);
outputStream.Write(base64IVBytes, 0, base64IVBytes.Length);
// Create a stream which, when we write bytes to it, turns those into
// base64 characters and writes them to outputStream
using var base64Stream = new CryptoStream(outputStream, new ToBase64Transform(), CryptoStreamMode.Write);
// Create a stream which, when we write bytes to it, encrypts them and sends them to
// base64Stream
using var encryptStream = new CryptoStream(base64Stream, aes.CreateEncryptor(), CryptoStreamMode.Write);
// Copy the entirety of our input file into encryptStream. This will encrypt them and
// push them into base64Stream, which will base64-encode them and push them into
// outputStream
inputStream.CopyTo(encryptStream);
请注意,使用 MD5 派生密钥字节不是最佳做法。使用 Rfc2898DeriveBytes
.
另请注意,您不一定需要在将加密结果写入文件之前对其进行 base64 编码——您可以直接将加密字节写入文件。为此,去掉 base64Stream
,并告诉 encryptStream
直接写入 outputStream
。
我正在尝试使用 AES 加密来加密一个大文件 (Camtasia.exe)。 现在由于某种原因我得到一个“内存不足”的异常。我对此很陌生,我不知道该如何解决。这是我的代码
我用这个来调用我的加密方法。
bytes = File.ReadAllBytes("Camtasia.exe");
Cryptography.Encryption.EncryptAES(System.Text.Encoding.Default.GetString(bytes), encryptionKey);
这是 AES 加密本身
public static string EncryptAES(string content, string password)
{
byte[] bytes = Encoding.UTF8.GetBytes(content);
using (SymmetricAlgorithm crypt = Aes.Create())
using (HashAlgorithm hash = MD5.Create())
using (MemoryStream memoryStream = new MemoryStream())
{
crypt.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// This is really only needed before you call CreateEncryptor the second time,
// since it starts out random. But it's here just to show it exists.
crypt.GenerateIV();
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
}
string base64IV = Convert.ToBase64String(crypt.IV);
string base64Ciphertext = Convert.ToBase64String(memoryStream.ToArray());
return base64IV + "!" + base64Ciphertext;
}
}
这是我在顶部调用函数“EncryptAES”时再次遇到的错误。如果有人能解释这是怎么发生的以及如何解决它,我会很高兴 https://imgur.com/xqcLsKW
您正在将整个 exe 读入内存,将其解释为 UTF-16 字符串 (??!),将其转回 UTF-8 字节,然后对其进行加密。这种转换 to/from 字符串的方法非常糟糕。可执行文件不是人类可读的字符串,即使它是人类可读的字符串,您对使用的编码也一头雾水。我想你可以放弃整个字符串。
您还将整个内容读入内存(实际上是多次,因为整个字符串的原因),这很浪费。您不需要这样做:您可以逐位加密它。为此,请使用 Stream。
像这样的东西应该可以工作(未经测试):至少它可以理解一般概念。我们设置了一系列流,让我们可以逐位读取输入文件中的数据,并将它们逐位写入输出文件。
// The file we're reading from
using var inputStream = File.OpenRead("Camtasia.exe");
// The file we're writing to
using var outputStream = File.OpenWrite("EncryptedFile.txt");
using var HashAlgorithm hash = MD5.Create();
using var aes = Aes.Create();
aes.Key = hash.ComputeHash(Encoding.UTF8.GetBytes(password));
// Turn the IV into a base64 string, add "!", encode as UTF-8, and write to the file
string base64IV = Convert.ToBase64String(aes.IV) + "!";
byte[] base64IVBytes = Encoding.UTF8.GetBytes(base64IV);
outputStream.Write(base64IVBytes, 0, base64IVBytes.Length);
// Create a stream which, when we write bytes to it, turns those into
// base64 characters and writes them to outputStream
using var base64Stream = new CryptoStream(outputStream, new ToBase64Transform(), CryptoStreamMode.Write);
// Create a stream which, when we write bytes to it, encrypts them and sends them to
// base64Stream
using var encryptStream = new CryptoStream(base64Stream, aes.CreateEncryptor(), CryptoStreamMode.Write);
// Copy the entirety of our input file into encryptStream. This will encrypt them and
// push them into base64Stream, which will base64-encode them and push them into
// outputStream
inputStream.CopyTo(encryptStream);
请注意,使用 MD5 派生密钥字节不是最佳做法。使用 Rfc2898DeriveBytes
.
另请注意,您不一定需要在将加密结果写入文件之前对其进行 base64 编码——您可以直接将加密字节写入文件。为此,去掉 base64Stream
,并告诉 encryptStream
直接写入 outputStream
。