AES-Encrypt-then-MAC一个大文件与.NET [英] AES-Encrypt-then-MAC a large file with .NET
问题描述
我想在.NET中以最有效的方式加密大文件(让我们说64 GB)。
I want to encrypt a large file (lets say 64 GB) in the most efficient way in .NET.
我将如何实现:
- 创建一个
AesManaged
的实例来加密文件流(读64 GB) li>
- 将此流保存到磁盘(因为它是大容纳在内存中)(写64 GB)
- 创建一个
HMACSHA512
来计算保存文件的哈希值(读取64 GB) - 使用iv将磁盘保存加密数据(读取和写入64 GB)
- Create an instance of
AesManaged
to encrypt the stream of the file (read 64 GB) - Save this stream to disk (because it is to big to hold in memory) (write 64 GB)
- Create an instance of
HMACSHA512
to compute hash of the saved file (read 64 GB) - Save encrypted data with iv to disk (read & write 64 GB)
简化的C#代码:
using (var aesManaged = new AesManaged())
{
using (var msEncrypt = File.OpenWrite(@"C:\Temp\bigfile.bin.tmp"))
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
File.OpenRead(@"C:\Temp\bigfile.bin").CopyTo(csEncrypt);
new MemoryStream(iv).CopyTo(csEncrypt);
}
}
}
using (var hmac = new HMACSHA512(hmacKey))
{
hmacHash = hmac.ComputeHash(File.OpenRead(@"C:\Temp\bigfile.bin.tmp"));
}
byte[] headerBytes;
using (var memoryStream = new MemoryStream())
{
var header = new Header
{
IV = iv,
HmacHash = hmacHash
};
Serializer.Serialize(memoryStream, header);
headerBytes = memoryStream.ToArray();
}
using (var newfile = File.OpenWrite(@"C:\Temp\bigfile.bin.enc"))
{
new MemoryStream(MagicBytes).CopyTo(newfile);
new MemoryStream(BitConverter.GetBytes(headerBytes.Length)).CopyTo(newfile);
new MemoryStream(headerBytes).CopyTo(newfile);
File.OpenRead(@"C:\Temp\bigfile.bin.tmp").CopyTo(newfile);
}
此实现具有劣势,我创建了第二个文件,并且我从磁盘中多次读取64 GB 。
This implementation has the disadvantage that I created a second file and that I read multiple times 64 GB from disk.
是必需的吗?如何最小化磁盘IO和RAM分配?
Is the necessary? How to minimize disk IO and ram allocation?
推荐答案
我总是得到 CryptoStream
错了,所以请原谅我的伪代码。基本思想是链接流,以便明文被复制到加密的加密中,加密进而将数据写入到执行MACing的密码流,然后将其写入纯文件流:
I always get CryptoStream
s wrong, so please excuse my pseudocode. The basic idea is to "chain" streams, so that plaintext gets copied to a cryptostream which does the encryption, which in turn writes data to a cryptostream that does the MACing, which then writes to plain old file stream:
using(var encryptedFileStream = File.OpenWrite("..."))
using(var macCryptoStream = new CryptoStream(encryptedFileStream, mac, CryptoStreamMode.Write))
using(var encryptCryptoStream = new CryptoStream(macCryptoStream, encryptor, CryptoStreamMode.Write))
using(var inputFileStream = File.OpenRead("..."))
inputFileStream.CopyTo(encryptCryptoStream);
这样,您只需要单次通过64Gb。
This way, you only need a single pass through your 64 Gb.
现在,您必须在加密文件的开始处存储IV和MAC,所以首先调整大小:
Now, you'll have to somehow store the IV and MAC in the beginning of your encrypted file, so first "resize" it:
using(var encryptedFileStream = File.OpenWrite("..."))
{
var offset = YourMagicHeaderLength + IvLength + MacLength;
encryptedFileStream.SetLength(offset);
encryptedFileStream.Position = offset;
// The rest of the code goes here
}
然后,在加密和计算MAC之后,回到最初并写出来。
and then, after encrypting and computing MAC, rewind to the very beginning and write them out.
这篇关于AES-Encrypt-then-MAC一个大文件与.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!