首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PRNG决定论?

PRNG决定论?
EN

Cryptography用户
提问于 2014-12-30 17:12:26
回答 2查看 4.2K关注 0票数 5

看到getDefaultPRNG()在java.security.SecureRandom中,我非常不确定如何使用它。在我的桌面上,它使用sun.security.provider.NativePRNG,它是从/dev/random和/或/dev/urandom读取的,如果您不能直接访问操作系统,那么在Linux上它实际上是不可预测的(不确定的)。但是在Windows上,谁知道呢呢?当我在另一台机器或JVM上运行这段代码时,它可能会回到SHA1或其他确定性算法。

如果SecureRandom的输出实际上是不可预测的(开发/随机),那么web服务器就可以使用它来生成安全会话令牌,这些令牌给最终用户或多或少是原始的。但是如果它是确定性的(摘要),那么向最终用户公开足够的输出会有效地损害所有后续输出。

对于确定性PRNG,我应该用几个随机比特(例如,当前时间的低比特)模糊每个输出。这将使得猜测确定性RNG在其循环中的位置变得更加困难。OTOH,如果PRNG使用/dev/随机,并且低比特的时间已经被用作种子的一部分,那么再次使用这些比特是不必要的,甚至可能会适得其反。这两种“随机”数的使用模型是不相容的。

除非我能够确定SecureRandom正在产生什么样的输出,否则我无法正确地使用它。在我看来,这似乎是一个设计缺陷。我认为这个接口应该保证一个确定性的或者实际上是非确定性的PRNG.我认为对于所有PRNG的用户来说,这是一个必要的契约(不仅仅是Java的SecureRandom)。

请告诉我我错过了什么。

EN

回答 2

Cryptography用户

回答已采纳

发布于 2014-12-31 15:56:53

假设没有人搞砸了实现,那么您得到什么样的RNG就不重要了。这是因为所有的java.security.SecureRandom实现都应该是加密性强的,就像在RFC 1750§6.3中定义的那样:

6.3密码强序列在必须生成一系列随机量的情况下,对手可能会在序列中学习一些值。一般来说,他们不应该能够预测其他的价值,从他们知道的。…

这包括SHA1PRNG实现,它是所述,如下所示:

该算法以SHA-1作为PRNG的基础.它在与64位计数器连接的真正随机种子值上计算SHA-1哈希值,该计数器对每个操作递增1。从160位SHA-1输出中,只使用64位.

请注意以下两个细节:

  1. PRNG的内部状态由随机种子值和计数器组成,攻击者需要学习PRNG的内部状态才能预测生成器的未来输出。输出从不包含这些值,而是只包含它们的沙一散列。为了从输出中重建内部状态,攻击者必须在SHA-1上执行一个成功的预图像攻击,而目前认为这是不可行的。
  2. SHA-1哈希函数的输出被截断为64位,丢弃了60%的哈希函数。即使内部状态像许多非加密PRNG一样被传播,通过一个混合函数(这里是SHA-1)重复地输入先前的状态,这种截断应该足以阻止任何合理的攻击者重构完整的状态,因为他们实际上必须猜测状态的其余96位。

因此,即使SHA1PRNG的输出是确定性的(给定初始种子,而输出从未显示),任何攻击者都不应该能够使用当前已知的技术和可行的计算资源,根据观察到的过去的输出(甚至甚至区分其输出与真正的随机比特流)来预测其未来的输出。

现在,关于一些注意事项:

  • SHA1PRNG的安全性完全取决于种子值是否安全(即从足够大的概率集中秘密地随机选择,以抵御野蛮的猜测攻击)。如果不正确地播种生成器,则可能会丢失所有安全属性。通常,对nextBytes()的第一次调用应该从系统提供的随机性源自动为生成器注入种子。但是,如果在第一次调用这种自动播种不会发生。之前调用setSeed(),则会调用nextBytes()。在这种情况下,内部PRNG状态完全依赖于用户提供的种子,如果选择不当,则可能没有多少熵。(这特别容易造成混淆,因为在内部种子之后调用setSeed()只会将用户提供的种子混合到内部状态,因此永远不会降低输出的随机性。)此外,虽然自动播种应该是安全的,但在实践中可能并不总是这样。值得注意的是,Android上PRNG种子中的一个缺陷在2013年被用于安卓设备上运行比特币软件的人的偷比特币
  • 即使正确地使用了SecureRandom实例,PRNG的内部实现也可能存在损害其安全性的bug。以下是我发现的一篇文章,讨论了各种实现中的缺陷.

如果您不信任JRE提供的SHA1PRNG,一种选择是使用SecureRandom.getInstance("NativePRNG")而不是new SecureRandom()显式地请求NativePRNG实现。当然,这个调用在没有这样一个实现的系统上可能会失败,而且无论如何,仍然需要您信任OS本机PRNG,以及Java密码实现提供的Java接口。

另一种选择是实现您自己的(确定性的) 密码安全伪随机数发生器,例如HMAC_DRBG或NIST SP 800-90A中的CTR_DRBG (注意:做not使用双重_EC_DRBG!),并使用它生成随机数,可能是混合(即XORed)和OS本机PRNG的输出。这里棘手的部分是正确地播撒PRNG :如果您能够访问安全的wrong,您最好直接使用它;如果没有,您将不得不实现一些特殊的熵收集方案,这是很难的,而且很容易出错。

票数 2
EN

Cryptography用户

发布于 2014-12-31 00:57:25

这里的关键是,即使最后使用的算法是"SHA1PRNG",也会以某种方式收集一些熵,以生成初始化PRNG的种子。所以,这一切都取决于种子。在本例中,您可以在sun.security.provider.SecureRandom的代码中看到种子是由类sun.security.provider.SeedGenerator生成的。下面是这个类文档中的描述:

该类为SHA1PRNG密码强随机数生成器生成种子。种子使用两种技术中的一种,通过计算当前系统的活动或从熵收集装置产生。在默认技术中,种子是通过计算VM在给定时间段内循环的次数来产生的。这个数字大致反映了当时的机器负载。样品用置换(s-box)和XORed一起翻译.这一过程是非线性的,应防止样品“平均”。S盒子被设计成具有均匀的统计分布,它的具体值对种子的安全性并不重要。我们还创建了许多休眠线程,这些线程通过保持调度程序的繁忙而增加了系统的熵。20个这样的样本应该给我们大约160比特的随机性。这些值是由守护进程线程在后台收集的,从而允许系统继续执行其不同的活动,从而为随机种子添加熵。类还收集各种系统信息,有的机器依赖,有的不。然后,使用20个种子字节对此信息进行散列。替代上述方法的方法是从熵收集设备(如/dev/随机)中获取种子材料。这可以通过将securerandom.source安全属性的值设置为指定熵收集设备位置的URL,或者通过设置java.security.egd系统属性来实现。如果无法访问指定的URL,则使用默认的线程机制。

请注意,只有当您不亲自为SecureRandom对象添加种子时,此过程才会发生。如果你提供自己的种子,那么PRNG的输出显然将取决于该种子。

IMHO,我认为这个过程对于你的应用应该是完全好的,所以你不应该担心随机性来源的可预见性。

这里还有其他有趣的参考资料:

票数 4
EN
页面原文内容由Cryptography提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://crypto.stackexchange.com/questions/21092

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档