Java AES / GCM / NoPadding - 什么是cipher.getIV()给我? [英] Java AES/GCM/NoPadding - What is cipher.getIV() giving me?

查看:4357
本文介绍了Java AES / GCM / NoPadding - 什么是cipher.getIV()给我?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我的主要问题是: / p>

  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;

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

//输出发送给用户
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; //见问题#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;
}

//输入来自用户
byte [] decrypt(byte [] message)throws Exception {
if(message.length& 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 /计数器模式下的IV,组合键的灾难?

    • 当我有多个应用程序一次运行此代码时,它仍然安全,所有显示加密的消息给用户相同的src数据(可能在同一毫秒)?

    • 返回的IV是什么?它是一个原子计数器加上一些随机噪声?

    • 我需要避免 cipher.getIV()

    • 源代码实现 cipher.getIV()在某处可用,假设我使用Oracle JDK 8 + JCE无限强度扩展?


  2. b $ b

  3. #2和#3的身份验证标签总是16字节(128位)长?


  4. <的填充,这是否意味着我的加密消息总是 12 + src.length + 16 字节长? (因此我可以安全地将它们压缩成一个字节数组,为此我知道正确的长度?)


  5. 显示无限数字给予用户知道的常数src数据的src数据加密给用户?


  6. 我可以安全地向用户显示无限数量的src数据加密,如果src数据每次不同(例如包括 System.currentTimeMillis()或随机数)?


  7. 如果我在加密之前用随机数填充src数据,会有帮助吗?前面和后面说8个随机字节,或只在一端?


(因为这些问题都是关于同一个区块的我自己的代码,他们是强烈的相互关系,其他人可能/应该有相同的问题,当实现相同的功能,它感到错误的将问题分成多个帖子。我可以重新发布他们单独if这是更适合StackOverflow的格式。让我知道!)

解决方案

Q1: getIV()安全让我以这种方式使用?



是的,至少对于Oracle提供的实现。它是使用默认的 SecureRandom 实现单独生成的。因为它是12字节大小(GCM的默认值),那么你有96位的随机性。计数器重复的几率非常小。您可以在Oracle JDK所基于的OpenJDK(GPL'ed)中查找源代码。



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








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






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



它可以具有从64位到128位的字节中的任何大小,具有8位增量。如果它更小,它只包括认证标签的最左边的字节。您可以使用 <$ c指定其他尺寸的标记$ c> GCMParameterSpec 作为 init 调用的第三个参数。



请注意,GCM的强度很大程度上取决于标签的大小。我建议保持它128位。






如果您想要生成大量的密文, Q4:#2和#3,并且没有填充,这是否意味着我的加密消息总是12 + src.length + 16字节长? (因此,我可以安全地将它们压缩成一个字节数组,为此我知道正确的长度?)

请参阅上文。对于Oracle提供程序,这是这种情况。使用 GCMParameterSpec 确定。






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



实际上未绑定,是的。我会开始担心后约2 ^ 48加密。






Q6:是吗?如果src数据每次不同(例如包括System.currentTimeMillis()或随机数),我可以安全地向用户显示无限数量的src数据加密?



查看Q5的回答






Q7:如果我填充src数据加密前的随机数?前面和后面说8个随机字节,或只在一端?



不,它根本不会帮助。 GCM在下面使用CTR模式,因此它只是使用密钥流加密。它不会作为一个IV。如果你需要一个几乎无限数量的密文(高于2 ^ 48!),那么我建议你使用该随机数字和你的密钥作为密钥推导函数或KDF。 HKDF目前是最好的,但你可能需要使用Bouncy城​​堡或自己实施。


I'm using AES/GCM/NoPadding encryption in Java 8 and I'm wondering whether my code has a security flaw. My code seems to work, in that it encrypts and decrypts text, but a few details are unclear.

My main question is this:

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

Does that IV satisfy the requirement of "For a given key, the IV MUST NOT repeat." from RFC 4106?

I'd also appreciate any answers / insight for my related questions (see below), but that first question is bugging me the most. I don't know where to find source code or documentation that answers this.


Here is the full code, roughly. I apologize in case I introduced errors while writing this post:

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);
  }
}

Suppose that users cracking my secret key = game over.


More detailed questions / related questions:

  1. Is the IV returned by cipher.getIV() safe for me to use in this way?

    • Does it avoid the catastrophe of reusing the IV,key combination in Galois/Counter Mode?
    • Is it still safe when I have multiple applications running this code at once, all displaying encrypted messages to users from the same src data (possibly in the same millisecond)?
    • What's the returned IV made of? Is it an atomic counter plus some random noise?
    • Do I need to avoid cipher.getIV() and construct an IV myself, with my own counter?
    • Is the source code implementing cipher.getIV() available online somewhere, assuming I'm using Oracle JDK 8 + JCE Unlimited Strength extension?
  2. Is that IV always 12 bytes long?

  3. Is the authentication tag always 16 bytes (128 bits) long?

  4. With #2 and #3, and the lack of padding, does that mean my encrypted messages are always 12 + src.length + 16 bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)

  5. Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?

  6. Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including System.currentTimeMillis() or random numbers)?

  7. Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?

(Because these questions are all about the same block of my own code, and they are strongly related to each other, and others might/should have the same set of questions when implementing the same functionality, it felt wrong to split the questions into multiple posts. I can re-post them separately if that is more appropriate for StackOverflow's format. Let me know!)

解决方案

Q1: Is the IV returned by cipher.getIV() safe for me to use in this way?

Yes, it is at least for the Oracle provided implementation. It is generated separately using the default SecureRandom implementation. As it is 12 bytes in size (the default for GCM) then you have 96 bits of randomness. The chance that the counter repeats is abysmally small. You can look up the source in the OpenJDK (GPL'ed) which the Oracle JDK is based on.

I would however still recommend you to generate your own 12 random bytes as other providers may behave differently.


Q2: Is that IV always 12 bytes long?

It's extremely likely as it is the GCM default, but other lengths are valid for GCM. The algorithm will however have to do additional calculations for any other size than 12 bytes. Due to weaknesses it is strongly recommended to keep it at 12 bytes / 96 bits and API's may restrict you to that choice of IV size.


Q3: Is the authentication tag always 16 bytes (128 bits) long?

No, it can have any size in bytes ranging from 64 bits to 128 bits with 8 bit increments. If it is smaller it simply consists of the leftmost bytes of the authentication tag though. You can specify another size of tag using GCMParameterSpec as third parameter for your init call.

Note that the strength of GCM is strongly dependent on the size of the tag. I would recommend keeping it to 128 bits. 96 bits should be the minimum especially if you want to generate a lot of ciphertext.


Q4: With #2 and #3, and the lack of padding, does that mean my encrypted messages are always 12 + src.length + 16 bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)

See above. For the Oracle provider this is the case. Use GCMParameterSpec to be sure of it.


Q5: Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?

Virtually unbound, yes. I would start worrying after about 2^48 encryptions. In general you should however design for key change.


Q6: Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including System.currentTimeMillis() or random numbers)?

See answer to Q5


Q7: Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?

No, it would not help at all. GCM uses CTR mode underneath, so it would just be encrypted with the key stream. It would not act as an IV. If you need a virtually boundless number of ciphertexts (higher than 2^48!) then I would suggest you use that random number and your key for a key derivation function or KDF. HKDF is currently best of breed, but you may need to use Bouncy Castle or implement it yourself.

这篇关于Java AES / GCM / NoPadding - 什么是cipher.getIV()给我?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆