首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何处理"AES/GCM/NoPadding“的IV和身份验证标记?

如何处理"AES/GCM/NoPadding“的IV和身份验证标记?
EN

Stack Overflow用户
提问于 2015-08-06 17:14:32
回答 1查看 33.6K关注 0票数 54

我在Java8中使用AES/GCM/NoPadding加密,我想知道我的代码是否有安全缺陷。我的代码似乎可以工作,因为它加密和解密文本,但一些细节是不清楚的。

我的主要问题是:

代码语言:javascript
复制
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????

确实认为IV满足“对于给定的键,IV不能重复”的要求。来自

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

下面是完整的代码,大致如此。我道歉,以防我在写这篇文章时引入了错误:

代码语言:javascript
复制
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);
  }
}

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

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

在这个way?

  • Does中使用cipher.getIV()返回的IV对我来说安全吗?它避免了在伽罗瓦/计数器模式下重用IV键组合的灾难吗?
  • 当我有多个应用程序同时运行这段代码,都向用户显示来自相同src数据的加密消息时,它是否仍然安全?(可能在相同的millisecond)?
  • What's中,返回的IV由?它是一个原子计数器加上一些随机噪声吗?
  • 我需要避免cipher.getIV()而自己构造一个IV吗,用我自己的计数器?
  • 是实现cipher.getIV()的源代码,可以在网上找到,假设我使用的是OracleJDK8+ JCE无限强度extension?
  1. Is,IV总是12字节长?

  1. 是始终16字节(128位)长的身份验证标记吗?

使用#2和#3的

  1. ,并且没有填充,这是否意味着我的加密消息总是12 + src.length + 16字节长?(所以我可以安全地将它们压缩到一个字节数组中,我知道它的正确长度是多少?)

  1. 在给定用户知道的常量src数据的情况下,向用户显示无限数量的src数据加密对我来说安全吗?

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

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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-08-07 02:27:49

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数据加密对我来说安全吗?

请参阅Q5和Q7的答案

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

不,这根本帮不上忙。GCM在底层使用CTR模式,因此它将只使用密钥流进行加密。现在,如果您有一个不断变化的消息要加密,您可以查看AES-GCM-SIV,但请注意,该算法在任何JCA提供商中都没有实现。

如果您需要大量密文(大于2^48!,或者2^32 -~40亿),那么我建议您使用这个随机数和密钥作为密钥派生函数或KDF。HKDF目前是最好的,但您可能需要使用Bouncy Castle或自己实现它。

票数 61
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31851612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档