58

使用标准 JDK 在 Java 中生成安全、随机 AES 密钥的推荐方法是什么?

在其他帖子中,我发现了这一点,但使用 aSecretKeyFactory可能是一个更好的主意:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random 
keyGen.init(random); 
SecretKey secretKey = keyGen.generateKey();

如果答案包括解释为什么它是生成随机密钥的好方法,那就太好了。谢谢!

4

3 回答 3

89

我会使用您建议的代码,但稍微简化一下:

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // for example
SecretKey secretKey = keyGen.generateKey();

让提供者选择它计划如何获得随机性 - 不要定义可能不如提供者已经选择的东西。

此代码示例假定(正如 Maarten 在下面指出的那样)您已将java.security文件配置为在列表顶部包含您的首选提供程序。如果要手动指定提供程序,只需调用KeyGenerator.getInstance("AES", "providerName");.

对于真正安全的密钥,您需要使用硬件安全模块(HSM) 来生成和保护密钥。HSM 制造商通常会提供一个 JCE 提供程序,使用上面的代码为您生成所有密钥。

于 2013-08-14T10:02:31.240 回答
23

使用KeyGenerator将是首选方法。正如邓肯所说,我肯定会在初始化期间给出密钥大小。KeyFactory是一种应该用于预先存在的密钥的方法。

好的,让我们来看看这个的本质。原则上,AES 密钥可以具有任何值。(3)DES 中没有“弱密钥”。也没有像 (3)DES 奇偶校验位那样具有特定含义的位。所以生成一个密钥可以像生成一个带有随机值的字节数组一样简单,然后SecretKeySpec在它周围创建一个。

但是您使用的方法仍然有优势:KeyGenerator专门为生成密钥而创建的。这意味着代码可能会针对这一代进行优化。这可能会带来效率和安全方面的好处。例如,它可能被编程以避免会暴露密钥的定时侧信道攻击。请注意,清除任何byte[]包含关键信息的信息可能已经是一个好主意,因为它们可能会泄漏到交换文件中(尽管如此)。

此外,如上所述,并非所有算法都使用完全随机的密钥。因此,使用KeyGenerator将更容易切换到其他算法。不过,更现代的密码将只接受完全随机的密钥;这被视为比 DES 的主要优势。

最后,就我而言,最重要的原因是,该KeyGenerator方法是在安全令牌(智能卡、TPM、USB 令牌或 HSM)中处理 AES 密钥的唯一有效方法。如果您使用 来创建byte[]SecretKeySpec则密钥必须来自内存。这意味着密钥可以放在安全令牌中,但无论如何密钥都会暴露在内存中。通常,安全令牌仅与在安全令牌中生成或通过例如智能卡或密钥仪式注入的密钥一起使用。AKeyGenerator可以由提供者提供,以便在安全令牌中直接生成密钥。

邓肯的回答所示:始终明确指定密钥大小(和任何其他参数)。不要依赖提供者默认值,因为这会使您的应用程序在做什么变得不清楚,并且每个提供者可能有自己的默认值。

于 2013-08-14T10:38:19.220 回答
7

其他帖子中有很多好的建议。这就是我使用的:

Key key;
SecureRandom rand = new SecureRandom();
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, rand);
key = generator.generateKey();

如果您需要另一个随机性提供程序,我有时会出于测试目的这样做,只需将 rand 替换为

MySecureRandom rand = new MySecureRandom();
于 2015-11-15T17:08:27.873 回答