如何在golang中使用AES256-GCM加密文件?

huangapple go评论90阅读模式
英文:

How to encrypt files with AES256-GCM in golang?

问题

AES256-GCM可以在Go中实现,代码示例可以参考https://gist.github.com/cannium/c167a19030f2a3c6adbb5a5174bea3ff。

然而,cipher.AEAD接口的Seal方法的签名是:

Seal(dst, nonce, plaintext, additionalData []byte) []byte

因此,对于非常大的文件,必须将所有文件内容读入内存,这是不可接受的。

一种可能的方法是在SealOpen上实现Reader/Writer接口,但这不应该由AEAD的块密码“模式”来解决吗?所以我想知道这是否是golang密码库的设计错误,或者我错过了与GCM相关的重要内容?

英文:

AES256-GCM could be implemented in go as https://gist.github.com/cannium/c167a19030f2a3c6adbb5a5174bea3ff

However, Seal method of interface cipher.AEAD has signature:

Seal(dst, nonce, plaintext, additionalData []byte) []byte

So for very large files, one must read all file contents into memory, which is unacceptable.

A possible way is to implement Reader/Writer interfaces on Seal and Open, but shouldn't that be solved by those block cipher "modes" of AEAD? So I wonder if this is a design mistake of golang cipher lib, or I missed something important with GCM?

答案1

得分: 2

AEAD(Authenticated Encryption with Associated Data)不应该用于一次性加密大量数据。该API的设计目的是阻止这种用法。

在单个操作中加密大量数据意味着:a)要么所有数据都必须保存在内存中,b)API必须以流式方式操作,返回未经身份验证的明文数据。

返回未经身份验证的数据是危险的,因为在互联网上很容易找到建议使用类似gpg -d your_archive.tgz.gpg | tar xz这样的命令来解密数据的人,因为gpg命令也提供了流式接口。

对于像AES-GCM这样的结构,如果应用程序在处理之前没有对明文进行身份验证,那么很容易随意篡改明文。即使应用程序小心地在身份验证建立之前不向用户界面公开明文,流式设计也会暴露更多的程序攻击面。

通过将大密文规范化并使用流式API,下一个使用该API的协议更有可能在不意识到问题的情况下使用它们,从而问题得以持续存在。

最好将明文输入分块成相当大的部分(比如16KiB)并分别加密。这些块只需要足够大,以至于额外认证器带来的开销可以忽略不计。通过这样的设计,可以逐步处理大型消息,而无需处理未经身份验证的明文,并且AEAD API可以更安全。(更不用说较大的消息可以被处理,因为AES-GCM等算法对于单个明文有64GiB的限制。)

需要一些思考来确保块的顺序正确,例如通过计数nonce,第一个块应该是第一个,即通过将nonce设置为零,最后一个块应该是最后一个,即通过附加一个带有特殊附加数据的空终止块。但这并不难。

有关示例,请参见miniLock中使用的分块方法。

即使使用这样的设计,仍然存在攻击者可以导致消息被可检测地截断的情况。如果要提高安全性,可以使用全有或全无变换,尽管这需要对输入进行两次处理,而且并非总是可行。

英文:

AEADs should not be used to encrypt large amounts of data in one go. The API is designed to discourage this.

Encrypting large amounts of data in a single operation means that a) either all the data has to be held in memory or b) the API has to operate in a streaming fashion, by returning unauthenticated plaintext.

Returning unauthenticated data is dangerous it's not
hard
to find people on the internet suggesting things like gpg -d your_archive.tgz.gpg | tar xzbecause the gpg command also provides a streaming interface.

With constructions like AES-GCM it's, of course, very easy to
manipulate the plaintext at will if the application doesn't
authenticate it before processing. Even if the application is careful
not to "release" plaintext to the UI until the authenticity has been
established, a streaming design exposes more program attack surface.

By normalising large ciphertexts and thus streaming APIs, the next
protocol that comes along is more likely to use them without realising
the issues and thus the problem persists.

Preferably, plaintext inputs would be chunked into reasonably large
parts (say 16KiB) and encrypted separately. The chunks only need to be
large enough that the overhead from the additional authenticators is
negligible. With such a design, large messages can be incrementally
processed without having to deal with unauthenticated plaintext, and
AEAD APIs can be safer. (Not to mention that larger messages can be
processed since AES-GCM, for one, has a 64GiB limit for a single
plaintext.)

Some thought is needed to ensure that the chunks are in the correct
order, i.e. by counting nonces, that the first chunk should be first, i.e. by starting the nonce at zero, and that the last chunk should be
last, i.e. by appending an empty, terminator chunk with special
additional data. But that's not hard.

For an example, see the chunking used in miniLock.

Even with such a design it's still the case that an attacker can cause
the message to be detectably truncated. If you want to aim higher, an
all-or-nothing transform can be used, although that requires two
passes over the input and isn't always viable.

答案2

得分: 1

这不是设计错误,只是API在这方面是不完整的。

GCM是一种流模式操作,因此能够在不停止流的情况下按需处理加密和解密。看起来你不能重用相同的AEAD实例与之前的MAC状态,所以不能直接使用这个API进行GCM加密。

你可以在crypto.NewCTR上实现自己的GCM,并使用自己实现的GHASH。

英文:

It's not a design mistake. It's just that the API is incomplete in that regard.

GCM is a streaming mode of operation and therefore able to handle encryption and decryption on demand without stopping the stream. It seems that you cannot reuse the same AEAD instance with the previous MAC state, so you cannot directly use this API for GCM encryption.

You could implement your own GCM on top of crypto.NewCTR and your own implementation of GHASH.

huangapple
  • 本文由 发表于 2016年9月6日 18:50:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/39347206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定