【问题标题】:AES-Encrypt-then-MAC a large file with .NETAES-Encrypt-then-MAC 使用 .NET 的大文件
【发布时间】:2016-07-28 15:21:23
【问题描述】:

我想以 .NET 中最有效的方式加密一个大文件(比如说 64 GB)。

我将如何实现:

  1. 创建AesManaged的实例以加密文件流(读取64 GB)
  2. 将此流保存到磁盘(因为它在内存中太大了)(写入 64 GB)
  3. 创建HMACSHA512 的实例以计算保存文件的哈希值(读取64 GB)
  4. 使用 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 和内存分配?

【问题讨论】:

  • 不,如果操作正确,则没有必要。此外,第 4 步很奇怪,因为应该在尝试加密之前创建 IV。在密文之前将IV写入文件是很常见的。

标签: c# encryption aes hmac


【解决方案1】:

我总是把CryptoStreams 弄错,所以请原谅我的伪代码。基本思想是“链接”流,以便将明文复制到进行加密的密码流中,然后将数据写入进行 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 存储在加密文件的开头,因此首先“调整”它的大小:

using(var encryptedFileStream = File.OpenWrite("..."))   
{
    var offset = YourMagicHeaderLength + IvLength + MacLength;
    encryptedFileStream.SetLength(offset);
    encryptedFileStream.Position = offset;

    // The rest of the code goes here
}

然后,在加密和计算 MAC 之后,倒回到最开始并写出来。

【讨论】:

  • 如果我想将一些数据添加到 hmac 但不添加到生成的文件流中怎么办?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-05
  • 2016-03-30
  • 1970-01-01
  • 2015-02-23
  • 2011-08-03
  • 1970-01-01
相关资源
最近更新 更多