我AES/GCM/NoPadding
在Java 8中使用加密,并且想知道我的代码是否存在安全漏洞。我的代码似乎可以 工作
,因为它可以加密和解密文本,但是一些细节尚不清楚。
我的主要问题是:
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以这种方式使用对我安全吗?
cipher.getIV()
自己和自己的柜台避免并建立静脉注射?cipher.getIV()
假设我使用的是Oracle JDK 8 + JCE Unlimited Strength扩展,是否可以在某个地方在线获得源代码实现?身份验证标签是否总是16个字节(128位)长?
使用#2和#3以及缺少填充,是否表示我的加密消息始终为12 + src.length + 16
字节长?(因此,我可以安全地将它们压缩到一个字节数组中,我知道该长度正确吗?)
给定用户已知的恒定src数据,对用户显示无数的src数据加密对我安全吗?
如果每次src数据都不相同(例如,包含System.currentTimeMillis()
或随机数),对用户显示无限数量的src数据加密是否对我安全?
如果在加密之前用随机数填充src数据会有所帮助吗?在前面和后面说8个随机字节,还是只说一端?还是完全没有帮助/会使我的加密变得更糟?
(由于这些问题都与我自己代码的同一块有关,并且彼此之间密切相关,并且在实现相同功能时其他人可能/应该具有相同的问题集,因此将这些问题分成多个部分是错误的如果适合于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大小 。
Q3:身份验证标签是否总是16个字节(128位)长?
不可以,它的字节大小可以从64位到128位以8位为增量的任意大小。如果较小,则仅由身份验证标签的最左侧字节组成。您可以将标签的另一个大小GCMParameterSpec
用作init
呼叫的第三个参数。
请注意,GCM的强度在很大程度上取决于标签的大小。我建议将其保留为128位。最少应包含96位, 特别是 如果您要生成大量密文时。
问题4:使用#2和#3,并且没有填充,这是否意味着我的加密消息始终为12 + src.length + 16个字节长?
(因此,我可以安全地将它们压缩到一个字节数组中,我知道该长度正确吗?)
往上看。对于Oracle提供程序,情况就是如此。使用GCMParameterSpec
来确保这一点。
Q5:在给定用户知道的恒定src数据的情况下,对用户显示无数的src数据加密是否安全?
几乎没有限制 ,是的。经过约2 ^ 48次加密后,我将开始担心。通常,您应该 设计 密钥更改。
Q6:如果每次的src数据都不相同(例如,包括System.currentTimeMillis()或随机数),对用户显示无数的src数据加密是否安全?
请参阅问题5的答案
问题7:如果在加密之前用随机数填充src数据会有所帮助吗? 在前面和后面说8个随机字节,还是只说一端?还是完全没有帮助/会使我的加密变得更糟?
不,完全没有帮助。GCM在下面使用CTR模式,因此只需使用密钥流进行加密即可。它 不会 充当IV。如果您需要几乎无数个密文(高于2 ^
48!),那么我建议您使用该随机数和密钥作为密钥派生函数或KDF。HKDF目前是最好的,但您可能需要使用Bouncy Castle或自己实施。
该IV是否满足“对于给定的密钥,IV不得重复”的要求。来自RFC 4106? 我也非常感谢对我相关问题的任何回答/洞察力(见下文),但第一个问题是最困扰我的。我不知道在哪里可以找到源代码或文档来回答这个问题。 下面是大致的完整代码。如果我在写这篇文章时引入了错误,我深表歉意: > 用cipher.getiv()返回的IV对我来说以这种方式使用安全吗? 它是否避免了在伽罗瓦/计数器模式下重复使用IV
问题内容: 我有一个简单的程序: 当我运行该程序时,我看到的只是用于输出。我原本希望我们会遇到第一轮,然后是,然后是etc。 这是由于这样的事实,一旦我们尝试在左侧重新声明,其值就会重置为? 如果有人可以指出我的详细情况,那将很棒。 更改为,似乎正在按预期方式打印数字。我对它达到最大32位值的速度感到惊讶! 问题答案: 该问题是由于整数溢出引起的。 在32位二进制补码算法中: 确实确实开始具有2的
我们试图在Java7中实现支持AES/GCM/NOPADDING的加密,以获得以下异常。 找不到任何支持AES/GCM/NOPADDING的提供程序 下面是生成密码实例的代码示例。
我正在尝试使用Nimbus JOSE+JWT从我的私钥解密JWE数据。 有人能帮我解决这个问题吗。我使用的是Java1.8 我的私钥 我的JWE数据
我在加密过程中尝试了以下选项: 但这会引发以下错误: