AES-Encrypt-then-MAC一个带.NET的大文件

时间:2016-07-27 21:16:46

标签: c# encryption aes hmac

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

我将如何实现这一点:

  1. 创建AesManaged实例以加密文件流(读取64 GB)
  2. 将此流保存到磁盘(因为它要保留在内存中)(写入64 GB)
  3. 创建HMACSHA512的实例以计算已保存文件的哈希值(读取64 GB)
  4. 使用iv将加密数据保存到磁盘(读取和写入64 GB)
  5. 简化的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和RAM配置?

1 个答案:

答案 0 :(得分:4)

我总是CryptoStream错了,所以请原谅我的伪代码。基本思想是“链接”流,以便将明文复制到执行加密的cryptostream,然后将数据写入执行MACing的cryptoverream,然后写入普通的旧文件流:

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之后,回到最开始并将它们写出来。