4

有很多问题询问 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 http://stackoverflow.com/questions/137212/how-to-solve-performance-problem-with-java-securerandom#comment68934647_137212
// 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?
4

2 回答 2

3

基本上,最好的答案是:你不知道。您最好将选择权留给专家并使用new SecureRandom(). 这将由具有最高优先级的提供者检索第一个随机数生成器。

存在哪些提供者以及哪个提供者具有优先级取决于运行时(IBM 和 Android 也有 Java 兼容的运行时)。运行时配置也可能因操作系统而异,即使对于标准 JDK 也是如此。

在虚拟机上,您应该安装特定 VM 管理器的操作系统特定客户端工具集;这通常允许客户端操作系统从主机操作系统播种。SecureRandom通常取决于主机提供种子甚至随机数据。但是,如果主机无法成功播种自己,那么 Java 运行时也将无法播种,并且在虚拟主机上创建的“随机数据”可能会重复。

JCA 文档

SecureRandom所有 Java SE 实现都使用无参数构造函数提供默认值: new SecureRandom(). 此构造函数遍历已注册安全提供程序的列表,从最喜欢的提供程序开始,然后从支持随机数生成器 (RNG) 算法SecureRandom的第一个提供程序返回一个新对象。SecureRandom如果没有提供程序支持 RNG 算法,则它返回一个SecureRandom使用来自 SUN 提供程序的 SHA1PRNG 的对象。


绝对没有必要自己“播种”算法。调用getSeed()将尝试从运行时检索种子。这可能会耗尽随机池,就像 一样getInstanceStrong(),导致您的应用程序和可能的其他应用程序阻塞,直到熵变得可用。如果您不提供种子,这些SecureRandom实现将自行播种 - 希望以尽可能最好的方式。请注意,在大多数(现代)实现中,提供的种子被混入随机池中,最初由操作系统播种;您不应该假设已提供相同种子的两个实例将生成相同的随机序列,即使在测试期间也不会,即使您明确指定"SHA1PRNG".

如果使用new SecureRandom()导致阻塞,那么您需要确保您的应用程序不/dev/random直接使用,从而耗尽熵池。如果它没有并且它仍然阻塞,那么/dev/random可能是行为不端。


对于检索长期密钥材料,您还可以使用SecureRandom.getInstanceStrong(). 不过,您通常不应该使用它;SecureRandom对于大多数用例来说应该足够强大。如果您使用该getInstanceStrong()方法,您可能会耗尽操作系统的熵池。


最好不要使用"SHA1PRNG". 即使所有运行时都有实现,但它不是实现要求

[1] 不需要特定的配置类型、策略类型或 SecureRandom 算法;但是,必须提供特定于实现的默认值。

请注意,Android 首先使用了不安全的"SHA1PRNG"实现,随后被 OpenSSL 本机代码取代。基本上,实现取决于使用了哪个 RNG。问题是 SHA1PRNG 的算法甚至没有被 Sun 指定,所以不可能依赖算法的任何细节,即使默认实现似乎是安全的。

于 2018-12-20T15:12:05.033 回答
-1

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

的文档getSeed()说:

仅包含此方法是为了向后兼容。鼓励调用者使用一种可选的 getInstance 方法来获取 SecureRandom 对象,然后调用 generateSeed 方法从该对象获取种子字节。

您当然可以完全按照说明进行操作,但我不确定您的其他示例是否有意义。

我不记得在哪里,但我很久以前读过,最好明确地给出算法。所以我通常这样做

SecureRandom.getInstance("SHA1PRNG")

对于SHA1算法;PRNG 用于伪随机数生成器。虽然 SHA1 已被用于一般加密目的,但有人告诉我,当您想将它们用作加密密钥时,它仍然适用于随机数。

于 2016-11-29T10:45:55.080 回答