javax.crypto.KeyGenerator 是否使用 /random 或 /urandom 生成密钥?

Does javax.crypto.KeyGenerator uses /random or /urandom to generate keys?

考虑以下代码片段,我在其中使用 AES-256 生成密钥进行加密 - 运行以下代码片段被阻止的线程。我怀疑这是否可能是由于未达到足够熵的问题。因此,线程可以暂停(或)看起来挂起,直到系统收集到足够的熵。

我 运行 这是在虚拟机上而不是在物理机上,我正在使用 Java8。

片段 A

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey key = keyGen.generateKey();

下面的article推断出SecureRandom实例当获得为

SecureRandom secureRandom = new SecureRandom();

默认用于生成熵的NativePRNG算法称为SHA1PRNG,默认使用/dev/urandom,因此不会发生线程阻塞。

我来谈谈我为什么要谈论这些东西。行

keyGen.init(256);

在上面的代码片段中,内部执行了以下操作。

 public final void init(int paramInt) {
     init(paramInt, JceSecurity.RANDOM);
 }

而这个JceSecurity.RANDOM有这个

static final SecureRandom RANDOM = new SecureRandom();

意味着它应该使用 /dev/urandom 并且当没有收集熵时这不应该被阻塞(或)挂起。

我在这里分享我的 java.security 文件。

有人可以解释为什么上面的 运行 是 SNIPPET A 阻塞的线程吗?

最终,随机数生成器将始终依赖于操作系统的熵源,即使只是为了播种;毕竟从非随机环境中生成随机数是不可能的。

我可以想象,熵源数量有限的 VM 很难填满条目池,即使只有一次。解决此问题的最佳方法是确保您的 VM 安装了最新的客户端。这些可以/应该使主机 RNG 可用于客户端计算机。

可以创建一个 SecureRandom 实例并将其作为参数传递给各种 init() 方法。但是,这并不能解决一开始就阻止它的问题,而且它会不必要地使代码复杂化。最后,您永远不会知道哪个库或模块仍在实例化另一个 SecureRandom 实例。

所以我会专注于修复客户端 VM 的 RNG 而不是 Java 代码。


注意 NativePRNG 直接使用 OS RNG;它不使用 "SHA1PRNG"SecureRandom() 使用包含 class 实现的第一个提供者;如果使用默认 PRNG,请确保您没有包含具有慢 PRNG 的提供程序。