如何在 Java 中创建安全的随机 AES 密钥?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18228579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create a secure random AES key in Java?
提问by barfuin
What is the recommended way of generating a secure, random AES key in Java, using the standard JDK?
使用标准 JDK 在 Java 中生成安全的随机 AES 密钥的推荐方法是什么?
In other posts, I have found this, but using a SecretKeyFactory
might be a better idea:
在其他帖子中,我发现了这一点,但使用 aSecretKeyFactory
可能是一个更好的主意:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random
keyGen.init(random);
SecretKey secretKey = keyGen.generateKey();
It would be great if the answer included an explanation of why it is a good way of generating the random key. Thanks!
如果答案包括解释为什么它是生成随机密钥的好方法,那就太好了。谢谢!
采纳答案by Duncan Jones
I would use your suggested code, but with a slight simplification:
我会使用你建议的代码,但稍微简化一下:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // for example
SecretKey secretKey = keyGen.generateKey();
Let the provider select how it plans to obtain randomness - don't define something that may not be as good as what the provider has already selected.
让提供者选择它计划如何获得随机性 - 不要定义可能不如提供者已经选择的东西。
This code example assumes (as Maarten points out below) that you've configured your java.security
file to include your preferred provider at the top of the list. If you want to manually specify the provider, just call KeyGenerator.getInstance("AES", "providerName");
.
此代码示例假定(正如 Maarten 在下面指出的那样)您已将java.security
文件配置为在列表顶部包含您的首选提供程序。如果要手动指定提供程序,只需调用KeyGenerator.getInstance("AES", "providerName");
.
For a truly secure key, you need to be using a hardware security module(HSM) to generate and protect the key. HSM manufacturers will typically supply a JCE provider that will do all the key generation for you, using the code above.
对于真正安全的密钥,您需要使用硬件安全模块(HSM) 来生成和保护密钥。HSM 制造商通常会提供一个 JCE 提供商,该提供商将使用上面的代码为您生成所有密钥。
回答by Maarten Bodewes
Using KeyGenerator
would be the preferred method. As Duncan indicated, I would certainly give the key size during initialization. KeyFactory
is a method that should be used for pre-existing keys.
使用KeyGenerator
将是首选方法。正如邓肯指出的那样,我肯定会在初始化期间给出密钥大小。KeyFactory
是一种应该用于预先存在的密钥的方法。
OK, so lets get to the nitty-gritty of this. In principle AES keys can have any value. There are no "weak keys" as in (3)DES. Nor are there any bits that have a specific meaning as in (3)DES parity bits. So generating a key can be as simple as generating a byte array with random values, and creating a SecretKeySpec
around it.
好的,让我们来了解一下它的本质。原则上,AES 密钥可以具有任何值。没有 (3)DES 中的“弱密钥”。也没有像 (3)DES 奇偶校验位那样具有特定含义的任何位。因此,生成密钥可以像生成具有随机值的字节数组并SecretKeySpec
在其周围创建一个一样简单。
But there are still advantages to the method you are using: the KeyGenerator
is specifically created to generate keys. This means that the code may be optimized for this generation. This couldhave efficiency and security benefits. It might be programmed to avoid a timing side channel attacks that would expose the key, for instance. Note that it may already be a good idea to clear any byte[]
that hold key information as they may be leaked into a swap file (this may be the case anyway though).
但是您使用的方法仍然有优势:它KeyGenerator
是专门为生成密钥而创建的。这意味着代码可能会针对这一代进行优化。这可能会带来效率和安全方面的好处。例如,它可以被编程来避免会暴露密钥的定时侧信道攻击。请注意,清除任何byte[]
保存关键信息的内容可能已经是一个好主意,因为它们可能会泄漏到交换文件中(尽管如此,情况可能如此)。
Furthermore, as said, not all algorithms are using fully random keys. So using KeyGenerator
would make it easier to switch to other algorithms. More modern ciphers will only accept fully random keys though; this is seen as a major benefit over e.g. DES.
此外,如上所述,并非所有算法都使用完全随机的密钥。因此,使用KeyGenerator
将使切换到其他算法更容易。不过,更现代的密码只会接受完全随机的密钥;这被视为优于例如 DES 的主要优点。
Finally, and in my case the most important reason, it that the KeyGenerator
method is the only valid way of handling AES keys within a secure token (smart card, TPM, USB token or HSM). If you create the byte[]
with the SecretKeySpec
then the key mustcome from memory. That means that the key may be put in the secure token, but that the key is exposed in memory regardless. Normally, secure tokens only work with keys that are either generated in the secure token or are injected by e.g. a smart card or a key ceremony. A KeyGenerator
can be supplied with a provider so that the key is directly generated within the secure token.
最后,就我而言,最重要的原因是,该KeyGenerator
方法是处理安全令牌(智能卡、TPM、USB 令牌或 HSM)内 AES 密钥的唯一有效方法。如果您byte[]
使用 the创建,SecretKeySpec
则密钥必须来自内存。这意味着密钥可以放在安全令牌中,但无论如何密钥都会暴露在内存中。通常,安全令牌仅与在安全令牌中生成或由例如智能卡或密钥仪式注入的密钥一起使用。AKeyGenerator
可以与提供程序一起提供,以便在安全令牌中直接生成密钥。
As indicated in Duncan's answer: always specify the key size (and any other parameters) explicitly. Do not rely on provider defaults as this willmake it unclear what your application is doing, and each provider may have its own defaults.
正如邓肯的回答所示:始终明确指定密钥大小(和任何其他参数)。不要依赖于供应商违约,因为这将使它不清楚你的应用程序在做,每个供应商都可能有自己的缺省值。
回答by Andy
Lots of good advince in the other posts. This is what I use:
其他帖子中有很多很好的建议。这是我使用的:
Key key;
SecureRandom rand = new SecureRandom();
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, rand);
key = generator.generateKey();
If you need another randomness provider, which I sometime do for testing purposes, just replace rand with
如果您需要另一个随机性提供者,我有时会出于测试目的而这样做,只需将 rand 替换为
MySecureRandom rand = new MySecureRandom();