SecureRandom中nextXXX()函数和generateSeed()函数有何区别?

8
函数nextXXX()(例如nextInt(),nextFloat()和nextBytes())与Java的SecureRandom类中的generateSeed(int numBytes): byte[]有什么区别? "generateSeed"中的“种子生成算法”与安全随机生成器本身有何不同?

1
你读过JavaDocs了吗?它们对我来说似乎非常清晰... - DavidPostill
@DavidPostill 感谢您的评论,是的,在发布这个问题之前我已经阅读了Java文档。如果您能解释一下区别,那将非常有帮助。 - Ashok
为什么?如果您能解释一下您不理解Javadoc的哪个部分,那将非常有帮助。它们的区别在于它们并不相同。 - user207421
1
@EJP 修正了问题,我认为JavaDoc对generateSeed的作用并不是那么清晰,“种子生成算法”根本没有被指定。 - Maarten Bodewes
@owlstead 感谢您为了更清晰而编辑问题,是的,我正在寻找种子生成算法。 - Ashok
3个回答

12

generateSeed() 并不使用由随机数生成器生成的任何字节。相反,它只是一个 穿透到 SecureRandom 实现使用的熵源,在其自身需要种子时进行种子化


例如,在 Oracle 提供的 Java SE 上调用以下代码:

// initSeed is just zero valued bytes
byte[] initSeed = new byte[16];

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(initSeed);

byte[] seed = secureRandom.generateSeed(16);

byte[] data = new byte[16];
secureRandom.nextBytes(data);

System.out.printf("Seed: %s%n", Hex.toHexString(seed));
System.out.printf("Data: %s%n", Hex.toHexString(data));

对于seed,实际上会给出不同的值,而对于data,则总是给出相同的值。换句话说,generateSeed使用操作系统请求16字节的熵来生成种子,而随机数生成器只被initSeed初始化,因此总是生成相同的伪随机数流。

警告:这仅用于说明问题;您不应该依赖任何SecureRandom实例返回除随机字节之外的任何内容。关于setSeed的行为因不同的实现而异。Oracle的"SHA1PRNG"提供程序将其作为唯一的种子,其他提供程序可能会选择将其混合到PRNG状态中(例如,较新的Android实现始终会生成随机数据)。


3

随机数函数依赖于一个初始值,从该值生成一系列随机数(请了解PRNG - 伪随机数生成)。next函数将返回从该初始值(种子)生成的下一个数字。generateSeed()将为PRNG生成一个新的初始值。


不会重新启动我的机器。但是你可以使用它来启动或种植另一个生成器。 - Maarten Bodewes
这本来是一个非常通用的答案,抱歉。看起来提问者并没有完全理解概念,而是实现它的方式。 - roelofs
好的,但是最后一行并不正确,它本身并不能重新启动任何东西。如果你修正了它,我很乐意点赞。 - Maarten Bodewes

0
实际上,nextXYZ()generateSeed()做的事情完全相同,通常如此。 SecureRandom.nextBytes()SecureRandom.generateSeed()实际上只是简单的包装器,将调用转发到SecureRandomSpi.engineGenerateSeed()SecureRandomSpi.engineNextBytes(),它们分别包含实际的实现。 SecureRandomSpi的具体实现取决于所选的算法,当然!然而,对于Windows平台上的默认SecureRandom算法(即"Windows-PRNG"),我们可以从源代码中看到engineNextBytes()engineGenerateSeed()做的事情完全相同:它们调用一个名为PRNG.generateSeed()的本地方法,这是一个最终调用Win32 API函数CryptGenRandom()的C++函数,该函数来自操作系统
详细信息请参见此处。
实施"NativePRNG"算法在Linux/Unix和MacOS上是有点复杂的。但是,基本上,engineNextBytes()和engineGenerateSeed()再次都会最终进入相同的方法 - 即RandomIO.readFully()。该方法简单地从与/dev/[u]random关联的InputStream中读取"随机"字节,即内核随机数源。
有关详细信息,请参见此处:
所有其他的[Secure]Random.nextXYZ()方法,比如nextInt()nextLong()nextDouble(),都会调用一个名为next()内部方法,该方法提供了所需的随机数。而且,不足为奇的是,next()方法最终会调用nextBytes()方法 - 因此,在SecureRandom的情况下,会调用SecureRandomSpi.engineNextBytes()

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