基本上,最好的答案是:你不知道。你最好让专家来选择并使用new SecureRandom()
。这将检索具有最高优先级提供程序的第一个随机数生成器。
哪些提供程序存在以及哪个提供程序具有优先级取决于运行时(IBM和Android也具有Java兼容的运行时)。即使对于标准JDK,运行时配置也可能因操作系统而异。
在虚拟机上,您应该安装特定VM管理器的操作系统客户端工具集;这通常允许客户端操作系统从主机操作系统中获取种子。SecureRandom
通常依赖于主机提供种子或甚至随机数据。但是,如果主机无法成功地自我播种,则Java运行时也无法实现,并且在虚拟主机上创建的“随机数据”可能会重复。
来自JCA文档:
所有Java SE实现都提供了一个默认的
SecureRandom
,使用无参构造函数:
new SecureRandom()
。此构造函数遍历已注册的安全提供程序列表,从最优先的提供程序开始,然后从支持
SecureRandom
随机数生成器(RNG)算法的第一个提供程序返回一个新的
SecureRandom
对象。如果没有提供程序支持RNG算法,则返回一个使用SUN提供程序中的SHA1PRNG的
SecureRandom
对象。
绝对没有必要自己“播种”算法。调用getSeed()
将尝试从运行时检索种子。这可能会耗尽随机池,就像getInstanceStrong()
一样,导致您的应用程序以及其他应用程序的阻塞,直到熵变得可用。如果您不提供种子,则SecureRandom
实现将自行播种-希望以最佳方式-。请注意,在大多数(现代)实现中,提供的种子被混合到随机池中,该池最初由操作系统等进行播种;您不应假设已提供相同种子的两个实例将生成相同的随机序列,即使在测试期间也是如此,甚至如果您明确指定"SHA1PRNG"
也是如此。
如果使用new SecureRandom()
导致阻塞,则需要确保您的应用程序不直接使用/dev/random
,从而耗尽熵池。如果它没有并且仍然阻塞,则/dev/random
可能出现问题。
为获得长期密钥材料,您也可以使用SecureRandom.getInstanceStrong()
。但通常情况下不建议这样做;SecureRandom
对于大多数使用场景来说已足够强大。如果使用getInstanceStrong()
方法,可能会耗尽操作系统的熵池。请注意,在较新的系统上,这种情况发生的可能性较小。例如,在Linux上,/dev/random
和/dev/urandom
都指向同一伪随机数生成器。
最好不要使用"SHA1PRNG"
。尽管所有运行时都有实现,但这并不是实现要求:
[1] 不需要特定的配置类型、策略类型或SecureRandom算法;但必须提供一个实现特定的默认值。
请注意,Android最初使用了不安全的"SHA1PRNG"
实现,随后被OpenSSL本地代码替换。基本上,实现依赖于使用的RNG。问题在于,Sun甚至没有指定SHA1PRNG算法,因此即使默认实现似乎是安全的,也无法依赖算法的任何细节。