创建一个“好”的SecureRandom的最佳方法是什么?

8

有很多问题询问特定初始化的SecureRandom是否“好”,但我找不到一个经验法则。

创建“好”的随机SecureRandom的最佳方法是什么?

// Fast
// Is it a good random?
SecureRandom secureRandom = new SecureRandom()?

// Freezes for a few seconds after being used several times - until getting a random enough seed.
// See https://dev59.com/73VC5IYBdhLWcg3w9GA9#HiYaoYgBc1ULPQZF2vZ5
// Is it a good random?
SecureRandom secureRandom = new SecureRandom(SecureRandom.getSeed(20))?

// Freezes for a very long time. Waited minutes and still no return :(
SecureRandom secureRandom = new SecureRandom.getInstanceStrong()?

Other?
2个回答

5

基本上,最好的答案是:你不知道。你最好让专家来选择并使用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算法,因此即使默认实现似乎是安全的,也无法依赖算法的任何细节。


0

我认为,除非您有特殊要求,否则所有这些都足够好。

getSeed() 的文档说:

此方法仅包含用于向后兼容。建议调用者使用其中一种替代的 getInstance 方法获取 SecureRandom 对象,然后调用 generateSeed 方法从该对象获取种子字节。

当然,您可以按照说明进行操作,但我不确定是否比其他示例更好。

我记不清在哪里读到过,但很久以前就已经推荐明确给出算法了。所以我通常会这样做。

SecureRandom.getInstance("SHA1PRNG")

对于SHA1算法,PRNG是伪随机数生成器。虽然SHA1在一般的加密目的上已经有些过时了,但我被告知它仍然适用于随机数,尤其是当你想将它们用作加密密钥时。


另一个答案当然很详细,这个答案也没有问题。 - Arvind Kumar Avinash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接