我在Java8中使用AES/GCM/NoPadding
加密,我想知道我的代码是否有安全缺陷。我的代码似乎可以工作,因为它加密和解密文本,但一些细节是不清楚的。
我的主要问题是:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
确实认为IV满足“对于给定的键,IV不能重复”的要求。来自
我也很感谢对我的相关问题的任何回答/见解(见下文),但第一个问题最困扰我。我不知道在哪里可以找到解决这个问题的源代码或文档。
下面是完整的代码,大致如此。我道歉,以防我在写这篇文章时引入了错误:
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?
cipher.getIV()
而自己构造一个IV吗,用我自己的计数器?cipher.getIV()
的源代码,可以在网上找到,假设我使用的是OracleJDK8+ JCE无限强度extension?使用#2和#3的
12 + src.length + 16
字节长?(所以我可以安全地将它们压缩到一个字节数组中,我知道它的正确长度是多少?)System.currentTimeMillis()
或随机数),向用户显示无限数量的src数据加密是否安全?(因为这些问题都是关于我自己的代码的同一块,而且它们彼此之间有很强的相关性,而且其他人在实现相同的功能时可能/应该有相同的问题集,所以将这些问题分成多个帖子是错误的。如果这更适合StackOverflow的格式,我可以分别重新发布它们。让我知道!)
发布于 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或自己实现它。
https://stackoverflow.com/questions/31851612
复制相似问题