当前位置: 首页 > 知识库问答 >
问题:

Java aes/gcm/nopadding-cipher.getiv()给了我什么?

归德厚
2023-03-14
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);
  }
}

>

  • 用cipher.getiv()返回的IV对我来说以这种方式使用安全吗?

    • 它是否避免了在伽罗瓦/计数器模式下重复使用IV组合键的灾难?
    • 当我有多个应用程序同时运行此代码,并且所有应用程序都从相同的src数据(可能在相同的毫秒内)向用户显示加密消息时,是否仍然安全?
    • 退回的IV是什么做的?是原子计数器加上一些随机噪声吗?
    • 我是否需要避免cipher.getiv()并使用自己的计数器自己构造一个IV?
    • 实现cipher.getiv()的源代码是否可以在线获得,假设我使用的是Oracle JDK 8+JCE无限强度扩展?

    IV总是12字节长吗?

    身份验证标记是否总是16字节(128位)长?

    使用#2和#3,并且缺少填充,这是否意味着我的加密消息总是12+src.length+16字节长?(这样我就可以安全地将它们压缩成一个字节数组,我知道它的正确长度?)

    在给定用户知道的恒定src数据的情况下,我向用户显示无限数量的src数据加密是否安全?

    (因为这些问题都是关于我自己的代码的同一块的,而且它们彼此之间有很强的相关性,而其他人在实现相同的功能时可能/应该有相同的问题集,所以把这些问题拆分成多个帖子感觉是不对的。如果这对StackOverflow的格式更合适的话,我可以分别重新发布它们。让我知道!)

  • 共有1个答案

    燕英逸
    2023-03-14

    Q1:Cipher.getiv()返回的IV对我来说以这种方式使用安全吗?

    是的,至少对于Oracle提供的实现来说是这样。它是使用默认的securerandom实现单独生成的。由于它的大小为12字节(GCM的默认值),所以您有96位的随机性。反面重复的几率非常小。您可以在Oracle JDK所基于的OpenJDK(GPL'ed)中查找源代码。

    然而,我仍然建议您生成自己的12个随机字节,因为其他提供者的行为可能不同。

    Q2:IV总是12字节长吗?

    这是很有可能的,因为它是GCM默认值,但其他长度对GCM是有效的。然而,该算法必须对12字节以外的任何其他大小进行额外的计算。由于存在缺陷,强烈建议将其保持在12字节/96位,API可能会限制您选择IV大小。

    Q3:身份验证标记总是16字节(128位)长吗?

    不,它可以有任何大小的字节,范围从64位到128位,递增8位。如果它较小,它只是由身份验证标记的最左边的字节组成。您可以使用GCMParameterSpec作为Init调用的第三个参数指定另一个大小的标记。

    注意,GCM的强度很大程度上取决于标签的大小。我建议保持128位。96位应该是最小值,特别是如果您想生成大量的密文。

    Q4:使用#2和#3,并且缺少填充,这是否意味着我的加密消息总是12+src.length+16字节长?(这样我就可以安全地将它们压缩成一个字节数组,我知道它的正确长度?)

    见上文。对于Oracle提供程序,情况就是这样。使用gcmparameterspec来确定它。

    Q5:给定用户知道的持续src数据,我向用户显示无限数量的src数据加密是否安全?

    几乎没有束缚,是的。我会在大约2^48次加密后开始担心。然而,一般来说,您应该为密钥更改进行设计。

    Q6:如果每次src数据都不一样(例如包括System.CurrentTimeMillis()或随机数),那么我向用户显示无限数量的src数据加密是否安全

    见对问题5的答复

    如果我在加密之前用随机数填充src数据会有帮助吗?假设前后各有8个随机字节,还是只在一端?或者这对我的加密没有任何帮助/使我的加密变得更糟?

    不,这一点帮助都没有。GCM在下面使用CTR模式,所以它只需要用密钥流加密。它不会起到静脉输液的作用。如果您需要无穷无尽的密文(高于2^48!)那么我建议您使用这个随机数和您的密钥作为密钥派生函数或KDF。HKDF是目前最好的品种,但您可能需要使用弹性城堡或实现自己。

     类似资料:
    • 问题内容: 我在Java 8中使用加密,并且想知道我的代码是否存在安全漏洞。我的代码似乎可以 工作 ,因为它可以加密和解密文本,但是一些细节尚不清楚。 我的主要问题是: 该IV是否满足“对于给定的密钥,IV不得重复”的要求。 来自RFC 4106 ? 我也很感激我对相关问题的任何答案/见解(见下文),但第一个问题困扰我最多。我不知道在哪里可以找到答案的源代码或文档。 这是完整的代码,大致。如果写这

    • 我正在考虑使我的应用程序更安全,并了解正在发生的一切。 我在Spring Boot有一个登录名。该登录调用UserDetailsService实现,如下所示: 这为我创建了一个具有用户角色的会话,以便我可以配置网络安全配置器适配器等。 所以我的问题是,用JWT添加过滤器到底做了什么?SpringSecurity在默认情况下是否已经这样做了,因为我所做的已经创建了一个经过授权和身份验证的用户。 谢了

    • 问题内容: 我有一个简单的程序: 当我运行该程序时,我看到的只是用于输出。我原本希望我们会遇到第一轮,然后是,然后是etc。 这是由于这样的事实,一旦我们尝试在左侧重新声明,其值就会重置为? 如果有人可以指出我的详细情况,那将很棒。 更改为,似乎正在按预期方式打印数字。我对它达到最大32位值的速度感到惊讶! 问题答案: 该问题是由于整数溢出引起的。 在32位二进制补码算法中: 确实确实开始具有2的

    • 编写并测试您自己的函数char*funct(char*str,int x),反转字符串str(位置n的字符除外),并返回修改后的str作为结果。函数funct的用途可以是: 这是主要的: 你好CppepC ollH 应该是: 你好Cpp