我有一个基本问题。为什么在SecureRandom类中使用“SHA1PRNG”。如果有人对此进行解释,将很有帮助。提前致谢。
例如:
SecureRandom.getInstance(“SHA1PRNG”);
最佳答案
警告
我认为直接依赖此算法是不好的。请参阅this answer on SO,其中我展示了为什么依赖特定的SecureRandom
算法不好。
请注意,尽管大多数运行时都将提供具有"SHA1PRNG"
实现的提供程序,但是Java规范而不是要求算法的实现,因此,如果仅假设它始终存在,那么NoSuchAlgorithmException
可能会失败。
简短的介绍"SHA1PRNG"
是伪随机数生成器的名称(名称中为PRNG)。这意味着它使用SHA1哈希函数来生成随机数流。 SHA1PRNG是当时Sun引入的专有机制。
实施的优点是PRNG独立于操作系统运行,它不依赖于/dev/random
或/dev/urandom
。这可能会带来性能上的好处,也可能有助于防止OS熵池(系统随机性所依赖的数据)的耗尽。
算法的性质
SHA1散列函数用于创建RNG的输出,并对在PRNG中使用的种子信息进行散列。 SHA1PRNG输出与内部状态解耦(因此,攻击者无法仅使用RNG的输出来重新创建内部状态)。
内部状态相对较大(对于Java 1.7中的SHA1PRNG,当前限制为散列大小为160位)。这意味着几乎不可能创建周期。如果多次遇到相同的内部状态,则会创建一个循环-以下状态也将相同(除非使用 setSeed()
添加其他熵)。
不幸的是,没有可用的算法的清晰描述,并且不同的提供程序可能会以不同的方式实现该算法,通常试图模仿Java的实现(有时是严重的甚至是不安全的)。
确定性操作
PRNG是确定性的。这意味着它们将始终从相同的输入材料(“种子”)生成相同的随机数流。但是,当首次访问随机池时,SUN SHA1PRNG将从从操作系统中检索到的熵中获得种子。在那种情况下,随机值将与真正的随机数生成器无法区分。
SUN SHA1PRNG的一个特殊属性是,如果在使用setSeed()
方法之一访问随机池以检索随机值之前调用了种子,则它将仅使用nextXxx()
给定的种子。在这种情况下,流将仅取决于给定的种子和实现的算法;在这种情况下,PRNG是完全确定的;如果调用相同的方法,它将始终返回相同的“随机”值。
这在测试期间可能很有用,但请不要在生产代码中依赖此属性。甚至SUN SHA1PRNG的实现也发生了变化,因此您不能依靠输出在不同版本上保持不变。
笔记
请注意,在JCA提供程序/不同的运行时中,SHA1PRNG的实现可能有所不同。与SUN SHA1PRNG相比,Android上的代码尤其不同且不稳定。 请仅将SecureRandom
用于其预期目的:生成安全的随机值。