计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列。
内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。
内核提供了两个字符设备: /dev/random和/dev/urandom,其read函数(random_read()和urandom_read())用于向用户模式程序输出随机数序列。上层应用程序可以通过read系统调用从它们获取随机数序列。相对于/dev/urandom接口,/dev/random输出的随机数序列质量更高,适合于高强度的加密算法。/dev/urandom总是返回所请求的随机数序列,无论熵池的熵估算值是否为零;而/dev/random则只返回熵估算值所允许的最长的随机数序列,当熵估算值为零时,请求将被阻塞直到熵估算值增大到一定域值。
上述输出接口最终均是通过调用 extract_entropy()函数输出随机数序列。Extract_entropy()函数使用SHA或MD5算法散列(Hash)熵池,将散列后的结果作为随机数序列输出给用户使用,这样避免了直接访问熵池中的内容。由于从SHA或MD5算法散列的结果反推原始数据的可能性几乎为零,所以这种设计极大的提高了安全性。攻击者无法直接访问熵池,也无法根据过去的随机数序列预测将来的序列。
当系统启动的时候,由于启动过程是个确定的可预测的过程,这种情况下,熵池的熵值将非常小,导致产生的随机数序列质量下降,从而给攻击者破解的可能。为了克服系统启动过程的可预测性带来的影响,Linux操作系统在系统关机的时候保存当前熵池的内容,当系统下次启动的时候恢复上次关机时熵池的数据,这样就有效增加了熵池的熵估算值,避免了随机数序列质量的下降。