怎样安全的生成随机数?

使用 urandom

使用 urandom。使用 urandom。使用 urandom。使用 urandom。使用 urandom。就是使用 urandom。


对于加密密钥呢?

依然是使用 urandom。


为什么不用 SecureRandom、OpenSSL、havaged 或 C 语言直接实现呢?

它们都是用户态的密码学随机数生成器。你更需要使用内核态的随机数生成器,这是因为:

  • 内核有权访问裸设备的熵。

  • 它可以确保不在应用程序间共享相同的状态。

  • 一个好的内核态随机数生成器,就如同 BSD 系统的,也会保障在未提供种子前不会为你提供数据。

通过研究过去十年来的随机数失败事件,你会看到大量的用户态随机数失败案例。Debian 中的 OpenSSH 瓦解原因?用户态随机数。安卓 Bitcoin 钱包中的的 ECDSA 算法的重复 k 问题? 用户态随机数。赌博网站的骰子可预测?用户态随机数。

不管怎样,用户态的生成器几乎总是依赖于内核的生成器。即使不这样,你的整个系统的安全也会确保如此。用户态的随机数生成器并没有提升纵深防御;相反,它只产生了两个单点故障。()


联机帮助页不是说使用 /dev/random 吗?

你应该忽略这个联机帮助页。不要使用 /dev/random 。/dev/random 和 /dev/urandom 的不同是 UNIX 的设计缺陷。联机帮助页不想承认,所以它产生了一个并非真正存在的安全问题。把 random(4) 中的密码学上的建议当作个传闻,继续你的生活。


但如果我需要真正的随机数,而不是伪随机数呢?

urandom 和 /dev/random 都提供了同类的随机。与一般的看法相反,/dev/random 没有提供真正的随机数数据。就密码学而言,你并不经常的需要真正的随机。

uradom 和 /dev/random 都基于简单的想法。它们的设计都与流加密紧密相关:一段小密钥被拉伸成带有非预测值的不确定流。这里,密钥是熵,流是输出。

只有在 Linux 上,/dev/random 与 urandom 有着明确意义的不同。Linux 内核的密码学随机数生成器会定期的重新加密自己(通过收集更多的熵的方式)。但 /dev/random 也试着追踪它在内存池中的熵有多少,当它觉得熵不够时,也会偶尔罢工。这种设计同我把它弄明白了一样傻,在密钥流上判断还有多少密钥上,它类似基于块的 AES-CTR。

如果你使用 /dev/random 而非 urandom,你的程序会不可预期的挂起(或者,对于入侵者来说,确是非常可预期的),当 Linux 弄不明白它自己的随机数生成器是如何工作的时候。使用 /dev/random 会让你的程序不是那么稳定,但在密码学角度上也不会使其更安全。


这不是个陷阱吗?

不是,但是有个你要了解的 Linux 内核的 BUG,即使它并没有改变你应该使用的随机数生成器。

在 Linux 上,如果一启动你的软件就运行了,或者你的系统刚安装完就运行,你的代码就可能与随机数生成器处于竞争中。那样不好,如果你赢得了竞争,就能出现一个时间窗,你可以得到 urandom 的可预测的输出。这是 Linux 的一个 BUG,如果 你在 Linux 嵌入设备上开发平台级的代码,你就需要了解它。

这确实是 Linux 上 urandom 的一个问题(/dev/random 却不是)。这也是 Linux 内核的一个 BUG。但在用户态也很容易修正:启动时,显式的为 urandom 提供种子。长期以来,大多数的 Linux 发行版都会做这件事,却没有切换到一个不同的密码学随机数生成器。


其它的操作系统怎么办?

FreeBSD 和 OSX 去掉了 urandom 和 /dev/random 间的不同;两个设备的行为相同。

不幸的是,联机帮助页在解释为什么是这样时,做的很不到位,延续了 Linux 的 urandom 很恐怖的神话。

FreeBSD 的内核态密码学随机数生成器,不管你使用 /dev/random 还是 urandom,都不会阻塞。除非没有给它通过提供种子,这种情形下,两者都会阻塞。这种行为,与 Linux 不同,但是却有意义。

Linux 应该采用它。但如果你是个应用开发者,这就对你的影响很小:Linux、FreeBSD、iOS,不管怎么样,用 urandom 吧。


一言以蔽之:

使用 urandom。


后记

ruby-trunk Feature #9569

到现在为止,SecureRandom.random_bytes 在尝试检测 /dev/urandom 前会尝试检测 OpenSSL 是否可用。我认为应该倒过来。两种情形你都仅需要将随机字节展开,所以 SecureRandom 可以越过中间人(和第二个故障点),仅需直接的与 /dev/urandom 交互,如果它可用的话。

结论:

/dev/urandom 不适合用来直接生成会话密钥,以及频繁生成的应用级的随机数据。

    random(4) [联机帮助页]  GNU/Linux [所述] ...

感谢: Matthew Green, Nate Lawson, Sean Devlin, Coda Hale, and Alex Balducci 阅读了本文草稿。

合理警告:Matthew 大部分与我意见相同。


你可能感兴趣的:(urandom)