当前位置: 首页 > 面试题库 >

Java AES / GCM / NoPadding-cipher.getIV()给我什么?

徐瑞
2023-03-14
问题内容

AES/GCM/NoPadding在Java 8中使用加密,并且想知道我的代码是否存在安全漏洞。我的代码似乎可以 工作
,因为它可以加密和解密文本,但是一些细节尚不清楚。

我的主要问题是:

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????

该IV是否满足“对于给定的密钥,IV不得重复”的要求。 来自RFC
4106

我也很感激我对相关问题的任何答案/见解(见下文),但第一个问题困扰我最多。我不知道在哪里可以找到答案的源代码或文档。

这是完整的代码,大致。如果写这篇文章时出现错误,我深表歉意:

class Encryptor {
  Key key;

  Encryptor(byte[] key) {
    if (key.length != 32) throw new IllegalArgumentException();
    this.key = new SecretKeySpec(key, "AES");
  }

  // the output is sent to users
  byte[] encrypt(byte[] src) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] iv = cipher.getIV(); // See question #1
    assert iv.length == 12; // See question #2
    byte[] cipherText = cipher.doFinal(src);
    assert cipherText.length == src.length + 16; // See question #3
    byte[] message = new byte[12 + src.length + 16]; // See question #4
    System.arraycopy(iv, 0, message, 0, 12);
    System.arraycopy(cipherText, 0, message, 12, cipherText.length);
    return message;
  }

  // the input comes from users
  byte[] decrypt(byte[] message) throws Exception {
    if (message.length < 12 + 16) throw new IllegalArgumentException();
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
    cipher.init(Cipher.DECRYPT_MODE, key, params);
    return cipher.doFinal(message, 12, message.length - 12);
  }
}

假设用户破解我的密钥=游戏结束。

更详细的问题/相关问题:

  1. cipher.getIV()返回的IV以这种方式使用对我安全吗?

    • 是否可以避免在Galois / Counter模式下重用IV键组合的灾难?
    • 当我有多个同时运行此代码的应用程序都从同一src数据(可能在同一毫秒内)向用户显示加密消息时,仍然安全吗?
    • 返回的IV由什么制成?它是原子计数器加上一些随机噪声吗?
    • 我是否需要cipher.getIV()自己和自己的柜台避免并建立静脉注射?
    • cipher.getIV()假设我使用的是Oracle JDK 8 + JCE Unlimited Strength扩展,是否可以在某个地方在线获得源代码实现?
    • 该IV是否总是12个字节长?
  2. 身份验证标签是否总是16个字节(128位)长?

  3. 使用#2和#3以及缺少填充,是否表示我的加密消息始终为12 + src.length + 16字节长?(因此,我可以安全地将它们压缩到一个字节数组中,我知道该长度正确吗?)

  4. 给定用户已知的恒定src数据,对用户显示无数的src数据加密对我安全吗?

  5. 如果每次src数据都不相同(例如,包含System.currentTimeMillis()或随机数),对用户显示无限数量的src数据加密是否对我安全?

  6. 如果在加密之前用随机数填充src数据会有所帮助吗?在前面和后面说8个随机字节,还是只说一端?还是完全没有帮助/会使我的加密变得更糟?

(由于这些问题都与我自己代码的同一块有关,并且彼此之间密切相关,并且在实现相同功能时其他人可能/应该具有相同的问题集,因此将这些问题分成多个部分是错误的如果适合于StackOverflow的格式,我可以分别重新发布它们。让我知道!)


问题答案:

Q1:cipher.getIV()返回的IV以这种方式使用对我安全吗?

是的,至少是针对Oracle提供的实施。它使用默认SecureRandom实现单独生成。由于它的大小为12个字节(GCM的默认值),因此您具有96位的随机性。计数器重复的机会很小。您可以在Oracle
JDK所基于的OpenJDK(GPL版)中查找源。

但是,我仍然建议您生成自己的12个随机字节,因为其他提供程序的行为可能有所不同。

Q2:IV是否总是12个字节长?

这很有可能是因为它是GCM的默认值,但其他长度对于GCM
有效。但是,对于12字节以外的任何其他大小,该算法将不得不执行其他计算。由于弱点,强烈建议将其保留为12字节/ 96位,并且API
可能会限制您选择IV大小

Q3:身份验证标签是否总是16个字节(128位)长?

不可以,它的字节大小可以从64位到128位以8位为增量的任意大小。如果较小,则仅由身份验证标签的最左侧字节组成。您可以将标签的另一个大小GCMParameterSpec用作init呼叫的第三个参数。

请注意,GCM的强度在很大程度上取决于标签的大小。我建议将其保留为128位。最少应包含96位, 特别是 如果您要生成大量密文时。

问题4:使用#2和#3,并且没有填充,这是否意味着我的加密消息始终为12 + src.length + 16个字节长?
(因此,我可以安全地将它们压缩到一个字节数组中,我知道该长度正确吗?)

往上看。对于Oracle提供程序,情况就是如此。使用GCMParameterSpec来确保这一点。

Q5:在给定用户知道的恒定src数据的情况下,对用户显示无数的src数据加密是否安全?

几乎没有限制 ,是的。经过约2 ^ 48次加密后,我将开始担心。通常,您应该 设计 密钥更改。

Q6:如果每次的src数据都不相同(例如,包括System.currentTimeMillis()或随机数),对用户显示无数的src数据加密是否安全?

请参阅问题5的答案

问题7:如果在加密之前用随机数填充src数据会有所帮助吗? 在前面和后面说8个随机字节,还是只说一端?还是完全没有帮助/会使我的加密变得更糟?

不,完全没有帮助。GCM在下面使用CTR模式,因此只需使用密钥流进行加密即可。它 不会 充当IV。如果您需要几乎无数个密文(高于2 ^
48!),那么我建议您使用该随机数和密钥作为密钥派生函数或KDF。HKDF目前是最好的,但您可能需要使用Bouncy Castle或自己实施。



 类似资料: