为什么带有 GCM 的 AES-256 在密文大小上增加了 16 个字节?

问题描述

我正在使用 Golang 的加密包,特别是 crypto/aes,带有 32 字节的密钥(因此,AES-256)和 GCM 方法(Galois/计数器模式)。
我从一个文件中读取了多个 16384 字节的块,并生成了一个密码块、一个 GCM 方法和一个 12 字节的随机随机数。
然后,我将随机数添加到密文中,以便在解密时将它们拆分,以访问随机数(因为 12 字节的大小是已知的)。

人们会期望生成的密文是 16384 + 12 个字节 = 16396;但是,在实际加密时,我得到的大小为 16412 字节,因此添加了 16 字节。解密每个块后,我得到 16384 的“正常”大小。

这是一个快速示例。

block,_ := aes.NewCipher([]byte("W9FLKnyv397R82kKuFpfp6y8usGRf49a"))
gcm,_ := cipher.NewGCM(block)
nonce = make([]byte,gcm.nonceSize()) // nonceSize is 12 bytes
_,_ = io.ReadFull(rand.Reader,nonce) // populate nonce with random data


for {
    src := make([]byte,1024 * 16) // let's hypotise this src is a chunk of a file,full of 1024 * 16 bytes,so 16384

    encryptedBytes := gcm.Seal(nonce,nonce,src,nil) // this prepends the nonce to the src,thus adding 12 bytes in front of the encrypted string

    /*
    Now,encryptedBytes should be 16384 + 12 bytes long,but it is 16384 + 12 + 16.
    If I want to decrypt a chunk of the encrypted bytes,I need to use the size of 16384 + 12 + 16 and this makes it unpractical.
    */
}

这似乎不是因为 padding(也因为 GCM 不使用 padding)。

那么,为什么 AES 会在我的密文中添加 16 个字节?

解决方法

AES-GCM 提供机密性、完整性和身份验证。要提供最后两个,需要一个身份验证标签。

始终计算 16 字节的标签大小,并且在您的情况下附加。


更多详情;

  1. 密文大小:这始终等于明文大小,因为 AES-GCM 内部使用 CTR 模式进行加密,无需填充。

  2. Nonce/IV 大小:GCM 可以接受大的 nonce 大小(或小),但是,建议使用 12 字节,因为它不需要额外的过程。 12 字节以外的任何值都用 GHASH 处理;

     if len(IV) = 96 then 
         J_0 = IV || 0^{31}1
     else 
         J_0=GHASH_H(IV||0^{s+64}||len(IV_64))
    

    Nonce 通常被添加到消息中,这是密文大小的增加。

  3. 标签大小:GCM 始终输出 16 字节的标签大小。可以修剪它,但是,它会降低防伪的安全性。

    标签通常附加在密文中。

    遵守NIST Special Publication 800-38D (page 8)

    标签的位长,用 t 表示,是一个安全参数,如附录 B 所述。一般来说,t 可以是以下五个值中的任何一个:128、120、112、104 或 96。对于某些应用程序,t 可能是 64 或 32;附录 C 中给出了使用这两种标签长度的指南,包括在这些情况下对输入数据长度和密钥寿命的要求。

因此您可能会看到类似 (Nonce|ciphertext|tag)

的输出

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...