c# - C# 处理和加密大文件时内存不足
问题描述
我试图用 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 字节,然后对其进行加密。这种与字符串的转换非常糟糕。可执行文件不是人类可读的字符串,即使它是,你在使用哪种编码方面也很困惑。我认为您可以删除整个字符串。
您还将整个内容读入内存(实际上是多次,因为整个字符串内容),这很浪费。您不需要这样做:您可以逐位加密它。为此,请使用 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
。
推荐阅读
- python - NotFoundError:从检查点恢复失败。这很可能是由于检查点中缺少变量名称或其他图形键
- azure - 通过 Terraform 创建 Logic App 时的问题
- python - 将余弦模拟数组导出为带有标签的矩阵
- node.js - 如何删除深度嵌套的对象数组的注释
- node.js - 需要使用 try-catch 块确认回调和错误在 async.each 中的工作方式
- python - 索引 Numpy Python 中连续值的数量
- reactjs - React js,如何使用xml作为你的html设计
- javascript - 用户单击提交按钮时如何隐藏 iframe 表单
- aurelia2 - 使用 aurelia“buscar”作为函数时出错
- android - 如何在另一个应用程序中获取另一个应用程序创建的文件