AES-Encrypt-then-MAC 使用 .NET 的大文件
AES-Encrypt-then-MAC a large file with .NET
我想在 .NET 中以最有效的方式加密大文件(比如 64 GB)。
我将如何实现:
- 创建
AesManaged
实例加密文件流(读取64GB)
- 将此流保存到磁盘(因为内存太大)(写入 64 GB)
- 创建
HMACSHA512
的实例以计算已保存文件的哈希值(读取 64 GB)
- 使用 iv 将加密数据保存到磁盘(读写 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 来自磁盘。
有必要吗?如何最小化磁盘 IO 和内存分配?
我总是弄错 CryptoStream
,所以请原谅我的伪代码。基本思想是 "chain" 流,以便将明文复制到进行加密的密码流,然后将数据写入进行 MACing 的密码流,然后写入普通的旧文件流:
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);
这样,您只需要一次通过 64 Gb。
现在,您必须以某种方式将 IV 和 MAC 存储在加密文件的开头,因此首先 "resize" 它:
using(var encryptedFileStream = File.OpenWrite("..."))
{
var offset = YourMagicHeaderLength + IvLength + MacLength;
encryptedFileStream.SetLength(offset);
encryptedFileStream.Position = offset;
// The rest of the code goes here
}
然后加密运算MAC后倒回到最开始写出来
我想在 .NET 中以最有效的方式加密大文件(比如 64 GB)。
我将如何实现:
- 创建
AesManaged
实例加密文件流(读取64GB) - 将此流保存到磁盘(因为内存太大)(写入 64 GB)
- 创建
HMACSHA512
的实例以计算已保存文件的哈希值(读取 64 GB) - 使用 iv 将加密数据保存到磁盘(读写 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 来自磁盘。
有必要吗?如何最小化磁盘 IO 和内存分配?
我总是弄错 CryptoStream
,所以请原谅我的伪代码。基本思想是 "chain" 流,以便将明文复制到进行加密的密码流,然后将数据写入进行 MACing 的密码流,然后写入普通的旧文件流:
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);
这样,您只需要一次通过 64 Gb。
现在,您必须以某种方式将 IV 和 MAC 存储在加密文件的开头,因此首先 "resize" 它:
using(var encryptedFileStream = File.OpenWrite("..."))
{
var offset = YourMagicHeaderLength + IvLength + MacLength;
encryptedFileStream.SetLength(offset);
encryptedFileStream.Position = offset;
// The rest of the code goes here
}
然后加密运算MAC后倒回到最开始写出来