首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何加密Go中的大文件/字节流?

如何加密Go中的大文件/字节流?
EN

Stack Overflow用户
提问于 2018-03-29 01:16:33
回答 2查看 7.3K关注 0票数 20

我有一些大的文件,我想要AES加密,然后发送线路或保存到磁盘。虽然在加密流看来是可能的,但似乎存在针对这样做警告,相反,人们建议将文件分割成块,并使用GCM或crypto/nacl/secretbox。

由于真实性要求,数据流的处理更加困难。我们不能加密-然后MAC:从本质上说,我们通常不知道流的大小。我们不能在流完成后发送MAC,因为这通常是由被关闭的流所指示的。我们不能在飞行中解密一个流,因为我们必须看到整个密文才能检查MAC。试图保护流增加了问题的巨大复杂性,没有好的答案。解决方案是将流分解为离散的块,并将它们视为消息。

文件被分割成4 4KiB块。每个块每次被修改时都会得到一个新的随机128位IV。128位认证标签(GHASH)保护每个块不受修改.

如果大量数据被解密,则在验证身份验证标记之前,不总是能够缓冲所有解密的数据。将数据分割成小块解决了延迟身份验证检查的问题,但引入了新的验证检查。大块可以重新排序..。...because每个块都是单独加密的。因此,块的顺序必须以某种方式编码到块本身中,以便能够检测到任意数量的块的重新排列。

有实际密码学经验的人能为我指明正确的方向吗?

更新

在问完这个问题后,我意识到在不能将整个字节流放入内存(加密一个10 24文件)和字节流也是一个未知的长度之间有一个区别,这个长度可能会远远超过解码该流的需要(一个24小时的实时视频流)。

我最感兴趣的是大气泡,在开始需要解码之前,可以到达流的末端。换句话说,不需要同时将整个明文/密文加载到内存中的加密。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-29 01:48:46

正如您已经从您的研究中发现的那样,对于经过身份验证的大型文件加密,并没有很好的解决方案。

传统上有两种方法来处理这个问题:

  • 将文件分割成块,分别加密每个块,并让每个块拥有自己的身份验证标记。AES-GCM将是这方面使用的最佳模式。此方法会导致文件大小与文件大小成比例增大。对于每个块,您还需要一个独特的时间。您还需要一种方法来指示块从哪里开始/结束。
  • 使用AES-CTR与缓冲区加密,对每个加密数据缓冲区调用HMAC上的Hash.Write。这样做的好处是加密可以一次完成。缺点是解密需要一次验证HMAC,而另一次则需要实际解密。这里的优点是文件大小保持不变,加上IV和HMAC结果的大约48个字节。

这两个选项都不是理想的,但是对于非常大的文件(~2GB或更多),第二个选项可能是首选的。

我在Go中包含了一个使用下面第二种方法的加密示例。在这个场景中,最后48个字节是IV (16个字节)和HMAC的结果(32个字节)。还请注意IV的HMACing。

代码语言:javascript
复制
const BUFFER_SIZE int = 4096
const IV_SIZE int = 16

func encrypt(filePathIn, filePathOut string, keyAes, keyHmac []byte) error {
    inFile, err := os.Open(filePathIn)
    if err != nil { return err }
    defer inFile.Close()

    outFile, err := os.Create(filePathOut)
    if err != nil { return err }
    defer outFile.Close()

    iv := make([]byte, IV_SIZE)
    _, err = rand.Read(iv)
    if err != nil { return err }

    aes, err := aes.NewCipher(keyAes)
    if err != nil { return err }

    ctr := cipher.NewCTR(aes, iv)
    hmac := hmac.New(sha256.New, keyHmac)

    buf := make([]byte, BUFFER_SIZE)
    for {
        n, err := inFile.Read(buf)
        if err != nil && err != io.EOF { return err }

        outBuf := make([]byte, n)
        ctr.XORKeyStream(outBuf, buf[:n])
        hmac.Write(outBuf)
        outFile.Write(outBuf)

        if err == io.EOF { break }
    }

    outFile.Write(iv)
    hmac.Write(iv)
    outFile.Write(hmac.Sum(nil))

    return nil
}
票数 17
EN

Stack Overflow用户

发布于 2018-03-29 15:48:22

加密后使用HMAC是一种有效的方法。然而,HMAC可能非常慢,特别是如果使用SHA-2 .你实际上也可以对GMAC做同样的事情,GCM的底层MAC。找到一个实现可能很棘手,但是GMAC已经超过了密文,所以如果您真的想要的话,可以单独执行它。还有其他方法,例如用于TLS1.2和1.3的Poly1305和AES。

对于GCM (或CCM、EAX或任何其他经过身份验证的密码),您需要验证块的顺序。您可以通过创建一个单独的文件加密密钥,然后使用当前输入( 12字节IV)来指示块的数量来实现这一点。这将解决IV的存储问题,并确保各块处于有序状态。您可以使用KDF生成文件加密密钥(如果您有唯一的方法来指示该文件),或者使用主密钥包装随机密钥。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49546567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档