Encryption 使戈朗的GCM/CBC密码可流化

Encryption 使戈朗的GCM/CBC密码可流化,encryption,go,aes,Encryption,Go,Aes,Go中的GCM和CBC AES密码不能与StreamWriter或StreamReader一起使用,这迫使我将整个文件分配到内存中。显然,这对于大文件来说并不理想 我想通过将一些固定大小的块分配到内存中,并将它们提供给GCM或CBC,使它们可以流化,但我认为这可能是一个坏主意,因为这样设计它们肯定是有原因的 有人能解释一下为什么在不将整个文件分配到内存的情况下不能使用这些操作模式吗?简单的回答-这就是他们设计API的方式 CBC和GCM是非常不同的模式。GCM是AEAD模式(使用相关数据进行身份

Go中的GCM和CBC AES密码不能与StreamWriter或StreamReader一起使用,这迫使我将整个文件分配到内存中。显然,这对于大文件来说并不理想

我想通过将一些固定大小的块分配到内存中,并将它们提供给GCM或CBC,使它们可以流化,但我认为这可能是一个坏主意,因为这样设计它们肯定是有原因的


有人能解释一下为什么在不将整个文件分配到内存的情况下不能使用这些操作模式吗?

简单的回答-这就是他们设计API的方式

CBC和GCM是非常不同的模式。GCM是AEAD模式(使用相关数据进行身份验证加密)。你真的需要认证吗?如果不是,对于大文件,CBC是一个很好的选择。你也可以使用CTR或OFB,但它们是流媒体模式,对选择静脉注射非常严格

在执行任何操作之前,我建议您阅读这些模式。您必须至少了解它们需要哪些参数、用于什么目的以及如何生成这些参数

CBC
BlockMode
接口非常适合加密大文件。您只需要逐块加密。CBC需要填充,但Go没有实现。至少,我没看到。你必须设法解决这个问题

GCM GCM使用
AEAD
接口,它只允许您对整个消息进行加密和解密。绝对没有理由这样实施。GCM是一种流模式,它实际上非常适合流加密。唯一的问题是身份验证。GCM在末尾生成一个标签,其作用类似于MAC。要使用该标记,您不能只加密无穷无尽的数据流。您必须将其拆分为块,并分别对其进行身份验证。或者做一些其他的事情,但是在某个时候你必须阅读标签并验证它,否则使用GCM就没有意义了

一些库(包括Go)所做的是,它们在加密时隐式地在末尾附加该标记,并在解密时读取和验证该标记。我个人认为这是一个非常糟糕的设计。标记应该作为一个单独的实体提供,您不能仅仅假设它总是在末尾。这并不是Go实施中唯一的问题。 对不起,你的咆哮。最近我处理了一个特别糟糕的实现

作为一种解决方案,我建议您将流分割成块,并使用唯一的nonce单独加密它们(这非常重要)。每个块的末尾都有一个标记,您应该对此进行验证。这样,您就可以使用GCM身份验证。是的,它有点难看,但Go不允许您访问内部方法,因此您可以创建自己的加密API


作为替代方案,您可以找到不同的实现。甚至可能是一个C库。我可以推荐mbedtls。对我来说,这是我在API方面遇到的最好的实现。

这里有一个用于从块模式读取的流实现。您的里程可能会有所不同

type BlockReader struct {
    buf   []byte
    block cipher.BlockMode
    in    io.Reader
}

func NewBlockReader(blockMode cipher.BlockMode,reader io.Reader) *BlockReader {
    return &BlockReader{
        block: blockMode,
        in:    reader,
    }
}

func (b *BlockReader) Read(p []byte) (n int, err error) {
    toRead := len(p)
    mul := toRead/b.block.BlockSize()
    size := mul*b.block.BlockSize()
    if cap(b.buf) != size{
        b.buf = make([]byte,toRead,toRead)
    }

    read, err := b.in.Read(b.buf)
    if err != nil {
        return 0,err
    }

    if read < b.block.BlockSize(){
        return 0,io.ErrUnexpectedEOF
    }
    b.block.CryptBlocks(b.buf,b.buf)
    return copy(p,b.buf),nil
}
类型BlockReader结构{
buf[]字节
分组密码.BlockMode
in-io.Reader
}
func NewBlockReader(块模式密码.块模式,读卡器io.读卡器)*BlockReader{
返回和区块读取器{
块:块模式,
在:读者,
}
}
func(b*块读取器)读取(p[]字节)(n int,err error){
探路者:=len(p)
mul:=toRead/b.block.BlockSize()
大小:=mul*b.block.BlockSize()
如果盖(b.buf)!=尺寸{
b、 buf=make([]字节,toRead,toRead)
}
读取,错误:=b.in.read(b.buf)
如果错误!=零{
返回0,错误
}
如果读取
您可以使用GCM加密每个块。它的效率不如流,但它可以工作,而且这些天可能会“足够快”。我需要GCM流。