Java AES / GCM / NoPadding – 什么是cipher.getIV()给我的?
我在Java 8中使用AES/GCM/NoPadding
加密,我想知道我的代码是否存在安全漏洞。 我的代码似乎有效 ,因为它加密和解密文本,但一些细节尚不清楚。
我的主要问题是:
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制成的? 它是primefaces计数器还是一些随机噪声?
- 我是否需要避免使用
cipher.getIV()
并使用自己的计数器构建一个IV? - 假设我使用的是Oracle JDK 8 + JCE Unlimited Strength扩展,那么实现
cipher.getIV()
的源代码是否可以在线获取?
-
那个IV总是长12个字节吗?
-
身份validation标记总是16个字节(128位)长吗?
-
对于#2和#3,以及缺少填充,这是否意味着我的加密消息总是
12 + src.length + 16
个字节长? (所以我可以安全地将它们挤压成一个字节数组,我知道它的长度是正确的吗?) -
在给定用户知道的常量src数据的情况下,向用户显示无限数量的src数据加密是否安全?
-
如果每次src数据不同(例如包括
System.currentTimeMillis()
或随机数),向用户显示无限数量的src数据加密是否安全? -
如果我在加密前用随机数填充src数据会有帮助吗? 在前面和后面说8个随机字节,或者只在一端? 或者这根本没有帮助/使我的加密更糟糕?
(因为这些问题都是关于我自己的代码的相同块,并且它们彼此密切相关,而其他人在实现相同function时可能/应该具有相同的问题集,将问题分成多个问题感觉不对如果这更适合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大小 。
问题3:validation标签总是长16个字节(128位)吗?
不,它可以具有任何大小的字节,范围从64位到128位,增量为8位。 如果它更小,它只包含认证标签的最左边的字节。 您可以使用GCMParameterSpec
指定另一个标签大小作为init
调用的第三个参数。
请注意,GCM的强度很大程度上取决于标签的大小。 我建议将它保持为128位。 96位应该是最小的, 特别是如果你想生成大量的密文。
问题4:对于#2和#3,并且缺少填充,这是否意味着我的加密消息总是12 + src.length + 16字节长? (所以我可以安全地将它们挤压成一个字节数组,我知道它的长度是正确的吗?)
往上看。 对于Oracle提供商来说就是这种情况。 使用GCMParameterSpec
来确保它。
问题5:在给定用户知道的常量src数据的情况下,向用户显示无限数量的src数据加密是否安全?
几乎没有绑定,是的。 在大约2 ^ 48次加密后我会开始担心。 一般而言,您应该设计关键更改。
问题6:如果每次src数据不同(例如包括System.currentTimeMillis()或随机数),向用户显示无限数量的src数据加密是否安全?
见Q5的答案
问题7:如果我在加密前用随机数填充src数据会有帮助吗? 在前面和后面说8个随机字节,或者只在一端? 或者这根本没有帮助/使我的加密更糟糕?
不,它根本没用。 GCM在下面使用CTR模式,因此它将使用密钥流加密。 它不会充当IV。 如果您需要几乎无限数量的密文(高于2 ^ 48!),那么我建议您使用该随机数和密钥来获得密钥派生函数或KDF。 HKDF目前是最好的,但您可能需要使用Bouncy Castle或自己实施。