如何在 Java 中创建安全的随机 AES 密钥?
Posted
技术标签:
【中文标题】如何在 Java 中创建安全的随机 AES 密钥?【英文标题】:How to create a secure random AES key in Java? 【发布时间】:2013-08-16 05:16:01 【问题描述】:使用标准 JDK 在 Java 中生成安全、随机 AES 密钥的推荐方法是什么?
在其他帖子中,我发现了这一点,但使用 SecretKeyFactory
可能是一个更好的主意:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom(); // cryptograph. secure random
keyGen.init(random);
SecretKey secretKey = keyGen.generateKey();
如果答案包括解释为什么它是生成随机密钥的好方法,那就太好了。谢谢!
【问题讨论】:
这可能会帮助***.com/questions/10252449/is-aes-key-random @Tala 那是我找到cited code 的地方。但从那篇文章中,我无法就如何创建随机密钥以及为什么它是一种安全方式达成共识。 【参考方案1】:我会使用您建议的代码,但稍微简化一下:
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // for example
SecretKey secretKey = keyGen.generateKey();
让提供者选择它计划如何获得随机性 - 不要定义可能不如提供者已经选择的东西。
此代码示例假定 (as Maarten points out below) 您已将 java.security
文件配置为在列表顶部包含您的首选提供商。如果您想手动指定提供程序,只需调用KeyGenerator.getInstance("AES", "providerName");
。
要获得真正安全的密钥,您需要使用hardware security module (HSM) 来生成和保护密钥。 HSM 制造商通常会提供一个 JCE 提供程序,使用上面的代码为您生成所有密钥。
【讨论】:
通常我也会省略提供者名称。配置平台(例如,使用java.security
文件或使用Security.addProvider()
以编程方式配置Provider
等)。否则代码的可移植性会降低,并且不会让用户更改为例如无需更改应用程序代码的 HSM。
为什么需要指定提供者?默认行为是使用支持该算法的最高优先级已安装提供程序,这对我来说似乎足够了。
并非所有密钥生成方法都是平等的,您可能需要明确选择例如提供者的密钥生成方法。这尤其适用于安全令牌的提供者。不过,对于 AES,随机数生成器可能更重要 - 例如,您可能希望使用更慢、更安全、经 FIPS 认证的随机数生成器,而不是默认的。
keyGen.init(256); 有什么区别?或 keyGen.init(128); ?
@HemanthPeela 它定义了要生成的密钥的长度。 256 位密钥比 128 位密钥强。【参考方案2】:
使用KeyGenerator
将是首选方法。正如邓肯所说,我肯定会在初始化期间给出密钥大小。 KeyFactory
是一种应该用于预先存在的密钥的方法。
好的,让我们来看看这个的本质。原则上,AES 密钥可以具有任何值。 (3)DES 中没有“弱密钥”。也没有像 (3)DES 奇偶校验位那样具有特定含义的位。所以生成一个密钥可以像生成一个带有随机值的字节数组一样简单,然后在它周围创建一个SecretKeySpec
。
但您使用的方法仍有优势:KeyGenerator
专门用于生成密钥。这意味着代码可能会针对这一代进行优化。这可能具有效率和安全优势。例如,它可能被编程以避免会暴露密钥的定时侧信道攻击。请注意,清除任何包含关键信息的byte[]
可能已经是一个好主意,因为它们可能会泄漏到交换文件中(尽管如此)。
此外,如上所述,并非所有算法都使用完全随机的密钥。所以使用KeyGenerator
会更容易切换到其他算法。不过,更现代的密码将只接受完全随机的密钥;这被认为是一个主要的好处,例如DES。
最后,就我而言,最重要的原因是,KeyGenerator
方法是在安全令牌(智能卡、TPM、USB 令牌或 HSM)中处理 AES 密钥的唯一有效方法。如果您使用SecretKeySpec
创建byte[]
,则密钥必须来自内存。这意味着密钥可以放在安全令牌中,但无论如何密钥都会暴露在内存中。通常,安全令牌仅适用于在安全令牌中生成或由例如注入的密钥。智能卡或钥匙仪式。 KeyGenerator
可以与提供程序一起提供,以便直接在安全令牌中生成密钥。
如Duncan's answer 中所述:始终明确指定密钥大小(和任何其他参数)。不要依赖提供者的默认值,因为这会使你的应用程序在做什么变得不清楚,而且每个提供者可能有自己的默认值。
【讨论】:
【参考方案3】:其他帖子中有很多好的建议。这是我使用的:
Key key;
SecureRandom rand = new SecureRandom();
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256, rand);
key = generator.generateKey();
如果您需要另一个随机性提供程序(我有时会出于测试目的这样做),只需将 rand 替换为
MySecureRandom rand = new MySecureRandom();
【讨论】:
我第一次指定随机生成器,第二次指定要使用的 AES 密钥的长度(256)。它们是独立的初始化方法。以上是关于如何在 Java 中创建安全的随机 AES 密钥?的主要内容,如果未能解决你的问题,请参考以下文章
Android Okhttp/Retrofit网络请求加解密实现方案