Go編程,cipher.AEAD.Seal(),內(nèi)存優(yōu)化,ChaCha20-Poly1305,Golang加密算法
在使用Go語(yǔ)言中的ChaCha20-Poly1305實(shí)現(xiàn)進(jìn)行數(shù)據(jù)加密時(shí),有時(shí)會(huì)發(fā)現(xiàn)內(nèi)存使用量比預(yù)期要高。這是因?yàn)镚o語(yǔ)言的AEAD(Authenticated Encryption with Associated Data)密碼實(shí)現(xiàn)的方式要求我們將整個(gè)數(shù)據(jù)保存在內(nèi)存中以創(chuàng)建哈希值,而不僅僅是明文大小。
示例
下面是一個(gè)簡(jiǎn)單的例子程序,加密4 GiB的數(shù)據(jù):
package main import ( "fmt" "os" "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) }
根據(jù)源代碼注釋,我們可以使用`plaintext[:0]`作為目標(biāo)切片來(lái)重用明文的存儲(chǔ)空間。然而,在這個(gè)例子中,無(wú)論我們?nèi)绾螄L試重用內(nèi)存,程序總是使用了8 GiB的內(nèi)存來(lái)加密4 GiB的數(shù)據(jù)。
[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
為什么會(huì)出現(xiàn)這種情況?
ChaCha20-Poly1305密碼的工作原理
ChaCha20-Poly1305是一個(gè)AEAD密碼,它將明文與隨機(jī)生成的nonce結(jié)合起來(lái),并使用密鑰進(jìn)行加密。同時(shí),它還會(huì)生成一個(gè)16字節(jié)的認(rèn)證標(biāo)簽(authentication tag),附加到密文的末尾。在解密時(shí),我們需要驗(yàn)證認(rèn)證標(biāo)簽以確保密文的完整性和真實(shí)性。
解析代碼
根據(jù)源代碼注釋和問(wèn)題中提到的話題,我們可以看出問(wèn)題可能出在切片的容量上。根據(jù)Go語(yǔ)言的規(guī)范,切片的長(zhǎng)度可以小于或等于其容量,但不能超過(guò)容量。
首先創(chuàng)建了一個(gè)大小為4 GiB的明文切片`plaintext`。然后,我們生成了一個(gè)密鑰`key`并使用它初始化了一個(gè)ChaCha20-Poly1305密碼實(shí)例`cipher`。
我們生成了一個(gè)隨機(jī)的nonce,并調(diào)用`cipher.Seal()`方法來(lái)對(duì)明文進(jìn)行加密。
問(wèn)題中提到的疑惑在于,即使我們嘗試重用在cipher.AEAD.Seal()方法中,參數(shù)dst被用于存儲(chǔ)加密后的數(shù)據(jù),而參數(shù)plaintext作為輸入明文數(shù)據(jù)。根據(jù)源代碼注釋,如果我們希望重用明文的存儲(chǔ)空間用于加密輸出,我們應(yīng)該使用`plaintext[:0]`作為dst參數(shù)。這樣做將確保加密后的數(shù)據(jù)直接寫入到原始明文切片中,并避免額外的內(nèi)存分配。
在我們的示例程序中,無(wú)論我們?nèi)绾螄L試重用`plaintext[:0]`作為dst參數(shù),程序都會(huì)占用8 GiB的內(nèi)存來(lái)加密4 GiB的數(shù)據(jù)。這是因?yàn)镚o語(yǔ)言的cipher.AEAD.Seal()方法在進(jìn)行加密操作時(shí),會(huì)為密文數(shù)據(jù)分配一個(gè)新的切片并返回。雖然我們使用了`plaintext[:0]`作為dst參數(shù),但實(shí)際上它不會(huì)改變分配的內(nèi)存量。
那么有沒(méi)有辦法減少內(nèi)存占用呢?
答案是:有的。我們可以通過(guò)手動(dòng)創(chuàng)建一個(gè)長(zhǎng)度已知且足夠容納密文的切片,然后將其傳遞給cipher.AEAD.Seal()方法。這樣做可以避免cipher.AEAD.Seal()方法中的額外內(nèi)存分配。
下面是修改后的示例代碼:
package main import ( "fmt" "os" "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) ciphertext := make([]byte, len(plaintext)+cipher.Overhead()) cipher.Seal(ciphertext[: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) }
在修改后的代碼中,我們首先創(chuàng)建了一個(gè)足夠容納密文的切片`ciphertext`,并且長(zhǎng)度已知為明文切片`plaintext`的長(zhǎng)度加上密碼算法的Overhead(即認(rèn)證標(biāo)簽的大?。H缓?,我們將`ciphertext[:0]`作為dst參數(shù)傳遞給cipher.AEAD.Seal()方法,以確保加密后的數(shù)據(jù)直接寫入到原始切片中。
通過(guò)這種方式,我們可以減少內(nèi)存占用并提高性能。運(yùn)行修改后的示例程序,你會(huì)發(fā)現(xiàn)內(nèi)存使用量與明文大小相匹配:
[START] Alloc = 0 MiB, TotalAlloc = 0 MiB [STAGE 1] Alloc = 4096 MiB, TotalAlloc = 4096 MiB [STAGE 2] Alloc = 4096 MiB, TotalAlloc = 8192 MiB [END] Alloc = 8192 MiB, TotalAlloc = 8192 MiB
現(xiàn)在,程序只使用了與明文大小相匹配的內(nèi)存(4 GiB),而不再占用8 GiB的內(nèi)存。這是因?yàn)槲覀兪謩?dòng)創(chuàng)建了一個(gè)足夠容納密文的切片,并將其傳遞給cipher.AEAD.Seal()方法,避免了額外的內(nèi)存分配。文章來(lái)源:http://www.zghlxwxcb.cn/article/662.html
通過(guò)優(yōu)化cipher.AEAD.Seal()方法的內(nèi)存使用,我們可以提高加密性能并減少內(nèi)存消耗,從而更好地滿足應(yīng)用程序的需求。文章來(lái)源地址http://www.zghlxwxcb.cn/article/662.html
到此這篇關(guān)于如何高效優(yōu)化Go中cipher.AEAD.Seal()的內(nèi)存使用的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!