AES256-GCM可以在go中实现为https://gist.github.com/cannium/c167a19030f2a3c6adbb5a5174bea3ff
接口cipher.AEAD
的Seal
方法具有签名:
Seal(dst, nonce, plaintext, additionalData []byte) []byte
所以对于非常大的文件,必须将所有文件内容读入内存,这是不可接受的。
一种可能的方法是在Seal
和Open
上实现Reader
/Writer
接口,但这不应该通过AEAD的分组密码"模式"来解决吗?所以我想知道这是golang密码库的设计错误,还是我错过了一些重要的GCM?
不应该使用aead一次性加密大量数据。该API旨在阻止这种情况。
在单个操作中加密大量数据意味着a)要么所有数据必须保存在内存中,要么b) API必须以流方式操作,通过返回未经认证的明文。
返回未经验证的数据是危险的,它不是很难在互联网上找到像gpg -d your_archive.tgz.gpg | tar xz
这样的人,因为gpg命令也提供了一个流接口。
对于像AES-GCM这样的结构,当然,很容易如果应用程序不这样做,可以随意操作明文在处理之前对其进行身份验证。即使应用程序很小心不要"释放";明文到UI,直到真实性被验证建立一个流设计,暴露更多的程序攻击面。
通过规范化大型密文,从而流式传输api,下一个随之而来的协议更有可能在没有意识到的情况下使用它们
最好将明文输入分成相当大的块部分(比如16KiB)并单独加密。块只需要是大到足以使额外身份验证器的开销为可以忽略不计。有了这样的设计,可以增量地处理大消息无需处理未经身份验证的明文即可处理AEAD api可能更安全。(更不用说更大的信息可以例如,由于AES-GCM对单个文件有64GiB的限制,因此已处理明文)。
需要一些想法来确保块是正确的顺序,即通过计算随机数,第一个块应该是第一个,即从0开始,最后一个块应该是最后,即通过附加一个空的终止符块,使用special额外的数据。但这并不难。
可以参考miniLock中chunk的用法
即使有这样的设计,攻击者仍然可以造成要被可检测地截断的消息。如果你想志存高远,那么可以使用全有或全无转换,尽管这需要两个
这不是设计错误。只是在这方面API是不完整的。
GCM是一种流操作模式,因此能够在不停止流的情况下按需处理加密和解密。似乎您无法使用以前的MAC状态重用相同的AEAD实例,因此您不能直接将此API用于GCM加密。
你可以在crypto.NewCTR
和GHASH之上实现你自己的GCM。