我正在使用GO的ChaCha20-Poly1305实现来加密数据,但是由于我正在加密一些大文件,所以内存使用量比我预期的要高.我知道Go的AEAD密码实现意味着我们必须将整个数据保存在内存中,以便它创建散列,但内存使用量是明文的两倍.
以下试图加密4 GiB数据的小程序突出显示了这一点(在实际程序中,key
和nonce
不应为空):
package main
import (
"os"
"fmt"
"runtime"
"golang.org/x/crypto/chacha20poly1305"
)
func main() {
showMemUsage("START")
plaintext := make([]byte, 4 * 1024 * 1024 * 1024) // 4 GiB
showMemUsage("STAGE 1")
key := make([]byte, chacha20poly1305.KeySize)
if cipher, err := chacha20poly1305.New(key); err == nil {
showMemUsage("STAGE 2")
nonce := make([]byte, chacha20poly1305.NonceSize)
cipher.Seal(plaintext[:0], nonce, plaintext, nil)
}
showMemUsage("END")
}
func showMemUsage(tag string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Fprintf(os.Stdout, "[%s] Alloc = %v MiB, TotalAlloc = %v MiB\n", tag, m.Alloc / 1024 / 1024, m.TotalAlloc / 1024 / 1024)
}
根据crypto/cipher/gcm.go
的源代码(由AES-GCM和ChaCha20-Poly1305使用),有以下注释:
// To reuse plaintext's storage for the encrypted output, use plaintext[:0]
// as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
Seal(dst, nonce, plaintext, additionalData []byte) []byte
这意味着我应该能够重用内存,我已经try 过这样做,但这对我的应用程序使用的内存量没有任何影响-在调用Seal()
之后,我们总是使用8 GiB的内存来加密4 GiB的数据?
[START] Alloc = 0 MiB, TotalAlloc = 0 MiB
[STAGE 1] Alloc = 4096 MiB, TotalAlloc = 4096 MiB
[STAGE 2] Alloc = 4096 MiB, TotalAlloc = 4096 MiB
[END] Alloc = 8192 MiB, TotalAlloc = 8192 MiB
如果它是在重复使用内存(如所暗示的),那么我不应该指望会有任何大规模的增长,除了AEAD密码向密文添加了相对较小的哈希?