从计算机随机数谈起
我们知道,计算机是一个可预测的系统,因此不可能通过算法来产生真正的随机数。在计算机中,所谓的随机数通常都是伪随机数,就是通过随机算法计算出来的,可以被近似看作随机数的数值。常见的随机数算法有线性同余法(Linear Congruential Generator)、梅森旋转法(Mersenne twister)等,前者是大部分编译器采用的算法,随机性相对差一些;而后者是更为优秀的随机算法,随机性好,被 Python、Ruby 等语言用作默认的随机算法。
但是,随机算法的缺陷也是很明显的。一方面,随机性越好的算法计算复杂度越大;另一方面,即使随机性再好,也无法与真正的随机数相媲美。因此,产生真正的随机数是最理想的方法。
Linux 内核熵池
Linux 内核采用熵来描述数据的随机性。在物理学中,熵(entropy)是一个描述系统混乱程度的物理量,熵越大说明系统越无序、越混乱,不确定性越大。
虽然计算机本身可预测,但计算机的运行环境中充满了各种不可预知的噪声,例如来自设备驱动的噪声、随机的鼠标点击间隔、硬件设备发生中断的时间等等。
Linux 系统维护了一个专门用于收集上述噪声的熵池(entropy pool),这些噪声将被用于产生真正的随机数。
需要注意的是,产生真随机数依赖于熵池中的噪声资源。如果熵池资源耗尽,就需要等到收集足够多的环境噪声时,才能继续产生新的随机数。
/dev/urandom
Linux 提供了内核随机数生成器的接口,即字符设备/dev/random,该字符设备用于生成高质量的随机数,它会确保熵池资源足够时才生成随机数。如上面所说,当熵池为空时,对/dev/random 的读取操作将会阻塞,直到收集足够的噪声为止。
使用/dev/random 来生成随机数,很可能导致应用被阻塞。幸运的是,Linux 中还有另一个随机数生成器/dev/urandom,该字符设备是/dev/random 的非阻塞版本,准确说它是一个伪随机数生成器,它的随机数种子来自于熵池,不过即使熵池为空,/dev/urandom 仍然能产生随机数。
Linux 的 man(4)手册中这么写道:
/dev/random 是一个遗留下来的接口,在所有使用场景中,/dev/urandom 更受欢迎并且能满足要求。
复制代码
/dev/random 接口遗留下来的原因主要是早期/dev/urandom 所采用的密码算法未被大家信任,但现在,/dev/urandom 已经被广泛的采用了。
解决由/dev/random 引起的阻塞
目前,仍有一些应用使用/dev/random 来生成随机数,这些应用在运行时,可能由于熵池耗尽而阻塞。例如 tomcat7.0 以上的版本,依赖于该生成器来生成随机数,可能启动时便没有反应,实际上是等待熵池收集噪声。此外,strongSwan 生成 CA 时使用的 ipsec pki 命令也可能因此而阻塞。
解决该问题可以通过安装 havged 程序来解决。haveged 是一个简单易用的不可预测随机数生成器,基于 HAVEGE 算法。haveged 可以解决在某些情况下,系统熵过低的问题。
参考 man 手册
相关文章