Java AES/GCM/NoPadding 加密在 doFinal 之后不会增加 IV 的计数器

Posted

技术标签:

【中文标题】Java AES/GCM/NoPadding 加密在 doFinal 之后不会增加 IV 的计数器【英文标题】:Java AES/GCM/NoPadding encryption does not increment the counter of the IV after doFinal 【发布时间】:2021-02-06 19:54:30 【问题描述】:

当我使用默认的 AES/GCM 算法初始化 Cipher 对象时,它有一个随机的 12 字节 IV,但在调用 doFinal 后前 4 个字节没有增加并抛出 java.lang.IllegalStateException: Cannot重复使用相同的密钥和 IV 进行多次加密例外。

SecretKey secretKey = ...

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

byte[] iv1 = encCipher.getIV();
byte[] ctext = encCipher.doFinal("a".getBytes());
      
cipher.update("b".getBytes());
byte[] iv2 = encCipher.getIV();
ctext = encCipher.doFinal();

【问题讨论】:

你的问题是什么?你想完成什么? 也许我在滥用密码。我不明白如果它不增加,为什么它使用 12 字节 IV 而不是 16。我必须使用相同的 256 位密钥加密一个大文件,并将其分块并自动增加随机数的计数器。 为什么不对每个块使用随机 IV?如果块是独立的,那么您可以使用不同的 IV。如果不是,请先加密一次,然后再分块 请查看@Maarten Bodewes 对此主题的回答:crypto.stackexchange.com/a/41610/50189。 IV/nonce 长度建议为 96 位/12 字节是 a) 与其他程序的兼容性和 b) 任何其他长度都需要重新计算新的(内部)。 加密后无法拆分,因为密文会一直保存在内存中直到最后,如果文件很大会因为内存不足而抛出异常。 【参考方案1】:

java.lang.IllegalStateException: 不能重复使用相同的密钥和 IV 进行多次加密异常。

这是为了保护您,希望库至少在同一个 Cipher 对象下使用时保持这种行为。

AES-GCM 在内部使用 CTR 模式下的 AES 进行加密,而对于 CTR 模式,重复使用 (key,IV) 对是由于拖拽导致的机密性灾难性失败。

AES-GCM 使用 12 字节 IV/nonce,其余用于计数器。前两个计数器值是保留的,因此您最多可以加密 2^32-2 个块,这会产生 2^39-256 位,并在单个(IV,密钥)对下产生大约 68-GB。

12 字节随机数是NIST 800-38d 的标准。如果您提供的 nonce 不等于 12 字节,那么它将是 processed 和 GHASH,之后大小将是 12 字节。

if len(IV) = 96 then 
    J_0 = IV || 0^311
else 
    J_0=GHASH_H(IV||0^s+64||len(IV_64))

不建议您使用counter-based IV generation as suggested by NIST,因为它会使其随机化。此外,由于 GHASH 调用,它会使您的加密速度变慢。

当我使用默认的 AES/GCM 算法初始化 Cipher 对象时,它有一个随机的 12 字节 IV,但前 4 字节不会递增

这是预期的。对方再次设置为零。由于您的文件大于计数器支持的大小,您想继续留在原处吗? Divide the file and make chain.

另外,请参阅What are the rules for using AES-GCM correctly? 只要标签不正确,就不要使用明文。 有一种 AES-GCM-SIV 模式可以消除(IV,密钥)对的误用。它只会泄漏在相同的 IV 和密钥下再次发送相同的消息。 TLS 实际上对每条记录使用一个新的 (key,IV) 对,它最多有 2^14 字节,这可以防止内存填充攻击。假设您将内存用于解密 68-GB,那么您已经看到标签不正确。适合服务器的 DOS 攻击点。 使用 ChaCha20-Poly1305 比可用的 AES-GCM 容易得多。不过,它仍然存在 (IV,key) 重用问题。 有一个使用 192 位随机数和 64 位计数器的 XChaCha20。这可以安全地处理非常大的数据大小和随机数。

【讨论】:

"12 字节的 nonce 是 NIST 800-38d 的标准。如果您提供的 nonce 不等于 12 字节,那么它将使用 GHASH 进行处理,大小将为 12 字节在那之后。”如果我使用 GCMParameterSpec 对象手动设置 IV,它实际上是一个 16 字节的 IV 而不是 12。我知道 IV 必须使用一次,所以我认为 cipjer 对象在提交明文进行加密后会自动增加 iv 的计数部分。如果我输入 (ciphertex+tag) 来更新下一个文件段的 aad 会好吗? 密文对于 aad 来说太大了,可以是 1 到 2^64 之间的数字。因为是not processed yet! 你的文件是不是太大了? 是的,它很大。如果我将它分成 4mb 部分,通过它作为身份验证应该没有问题,应该是? 它有多大?一部手机超过 68GB?按照标准,aad 最多可以是 64 位。你必须使用 AES-GCM 吗?

以上是关于Java AES/GCM/NoPadding 加密在 doFinal 之后不会增加 IV 的计数器的主要内容,如果未能解决你的问题,请参考以下文章

JOSEException:无法创建 AES/GCM/NoPadding 密码:非法密钥大小

微信小微商户接口开发_java_相关问题汇总

net.schmizz.sshj.DefaultConfig Illegal key size问题,NIFI部分版本因此无法正常启动

net.schmizz.sshj.DefaultConfig Illegal key size问题,NIFI部分版本因此无法正常启动

java地址栏加密

des加密 c++ java