您如何在GO中加密大型文件 /字节流



我有一些大文件,我想在发送电线或保存到磁盘之前加密AES。虽然似乎可以加密流,但似乎有警告反对这样做,而是建议人们建议将文件分配到块中,并使用GCM或Crypto/NACL/Secretbox。

由于真实性要求,处理数据流更加困难。我们不能加密到麦克风:从本质上讲,我们通常不知道流的大小。流完成后我们无法发送Mac,因为通常通过关闭流来表示。我们不能即时解密流,因为我们必须查看整个密文才能检查Mac。试图保护流可以为问题带来巨大的复杂性,没有好的答案。解决方案是将流分解成离散的块,并将其视为消息。

  • https://leanpub.com/gocrypto/read

文件分为4KIB块。每个块每次修改时都会获得新的随机128位IV。128位身份验证标签(GHASH(可保护每个块免受修改。

  • https://nuetzlich.net/gocryptfs/forward_mode_crypto/

如果大量数据被解密,则直到验证身份验证标签之前,并非总是可以缓冲所有解密数据。将数据分成小块可以解决递延身份验证检查的问题,但引入了新的。可以重新排序这些块……因为每个块都是分开加密的。因此,必须将块的顺序以某种方式编码到块本身中,以便能够检测到任何数量的块。

  • https://github.com/minio/sio

任何具有实际密码学的人都可以将我指向正确的方向吗?

更新

我在问这个问题后意识到,根本无法将整个字节流安装到内存(加密10GB文件(和字节流也是一个未知的长度之间,这是有区别的可能会持续很长时间来解码流的需求(一个24小时的实时视频流(。

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

正如您已经从研究中发现的那样,对于 agen验证加密的优雅解决方案。

传统上有两种方法可以解决这个问题:

  • 将文件分成块,单独加密每个块,让每个块都有自己的身份验证标签。AES-GCM将是最佳使用模式。此方法导致文件大小与文件大小成比例。您还需要一个独特的nonce。您还需要一种方法来指示块从哪里开始/结束。

  • 使用带有缓冲区的AES-CTR加密,在HMAC上调用Hash.Write,以将其用于加密数据的每个缓冲区。这样做的好处是,加密可以在一次通过中进行。不利的一面是,解密需要一个通过来验证HMAC,然后再通过另一个通过才能真正解密。这里的好处是,文件大小保持不变,加上IV和HMAC结果的约48个左右的字节。

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

我使用以下第二种方法包括了GO中加密的示例。在这种情况下,最后48个字节是IV(16个字节(和HMAC的结果(32个字节(。请注意IV的Hmacing。

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
}

加密后使用HMAC是一种有效的方法。但是,HMAC可能非常慢,尤其是在使用SHA-2的情况下。实际上,您可以使用GMAC(GCM的基础Mac(做同样的事情。找到实现可能很棘手,但是GMAC超过了Ciphertext,因此,如果您真的需要,您可以单独执行它。还有其他方法,例如poly1305,其AE与TLS 1.2和1.3一起使用。

对于GCM(或CCM或EAX或任何其他身份验证的密码(,您需要对块的顺序进行身份验证。您可以通过创建一个单独的文件加密密钥,然后使用NONCE输入(12个字节IV(来执行此操作,以指示块的数量。这将解决IV 的存储,请确保块井井有条。您可以使用KDF生成文件加密密钥(如果您有指示文件的唯一方法(或通过将随机密钥包装到主密钥中。

最新更新