/dev/random 和 /dev/urandom 的原理

/dev/random/dev/urandom 是 Linux 上的字符设备文件,它们是随机数生成器,为系统提供随机数

随机数的重要性

随机数在计算中很重要。 TCP/IP 序列号、密码盐和 DNS 源端口号都依赖于随机数。

在密码学中,随机性无处不在,从密钥的生成到加密系统,甚至密码系统受到攻击的方式。没有随机性,所有加密操作都是可预测的,因此不安全。

随机数产生的原理

为了尽可能的做到随机,随机数生成器会收集系统环境中各种数据,比如:鼠标的移动,键盘的输入, 终端的连接以及断开,音视频的播放,系统中断,内存 CPU 的使用等等

生成器把收集到的各种环境数据放入一个池子 ( 熵池 ) 中,然后将这些数据进行去偏、漂白,主要目的也是使得数据更加无序,更加难以猜测或者预料得到

有了大量的环境数据之后,每次获取随机数时,从池子中读取指定的字节序列,这些字节序列就是生成器生成的随机数

随机数生成器的结构

下图是随机数生成器的结构

整个生成器的结构分成 收集器、主熵池、次熵池、urandom熵池、计数器 几部分

  • 收集器

收集器收集系统中的环境噪音,比如:鼠标、键盘、中断事件、内存、CPU等,收集之后进行批量去偏、漂白之后进入主熵池中

  • 主熵池

主熵池接收收集器传递过来的环境数据,大小为 512字节( 4098二进制位) , 它为 次熵池 和 urandom 熵池提供随机数

在 Linux上,可以通过下面的命令查看当前系统主熵池大小, 单位是 二进制位的数量

[root@localhost ~]# cat /proc/sys/kernel/random/poolsize
4096
  • 次熵池

/dev/random 设备关连的,大小为128字节,它是阻塞的

  • urandom 熵池

和 /dev/urandom 设备关连的,大小为128字节,它是非阻塞的

  • 计数器

主熵池 、次熵池 以及 urandom熵池各自都有一个计数器,用一个整数值来记录,表示当前熵池中可用随机数的数量,这是一个预估的值,它是生成器根据熵池中的环境数据估算出来的

当熵池中有新的随机数加入时,对应熵池的计数器计数会增加,当熵池中随机数被取出时,熵池计数器计数减少

输出接口

生成器主要有 /dev/random/dev/urandomget_random_bytes() 这三个接口

  • /dev/random、/dev/urandom

可以从用户空间去访问这两设备文件,即使是普通用户也有访问权限,它们返回指定请求数量的随机数

  • get_random_bytes()

只供内核使用的接口, 返回指定请求数量的随机数,暂时不讨论这个接口

请求随机数流程

现假如应用层分别调用 /dev/random/dev/urandom 请求 N 个随机二进制位,它们的处理流程如下:

  • /dev/urandom

urandom 熵池计数器计数会减去 N ,如果结果大于等于0 ,直接从urandom熵池中取出 N 个随机二进制位并返回,如果结果小于0,请求不会阻塞,只不过返回的是 N 个伪随机二进制位,这里的伪随机二进制位是通过算法计算出来的,它的质量没有 urandom 熵池中提取出的随机二进制位高

  • /dev/random

次熵池计数器减去 N, 如果结果大于等于0,直接从 次熵池中取出 N 个随机二进制位并返回

如果结果小于 0, 先从主熵池提取剩余所需的随机二进制位,主熵池计数器减去相应的值,同时返回 N 个随机二进制位

如果这时主熵池和次熵池两者计数器之和都不够 N 的话, 则读取随机二进制位的动作会被阻塞,直到次熵池中有足够的随机二进制位

/dev/random、/dev/urandom 的区别

/dev/urandom 它返回指定请求数量的随机数,如果请求的数量非常庞大的话,返回的随机数可能是伪随机数,随机数质量稍差些,即使如此,它们对大多数应用来说已经足够了

/dev/random 也是返回指定请求数量的随机数,但是它产生的随机数质量很高, 是属于真随机数, 主要用于需要高质量的随机数的地方,比如:生成加密密钥等。

为了保证随机数的质量,/dev/random 只能返回熵池当前最大可用的随机二进制位,当请求超过这个值,就会阻塞,直到熵池中有足够的随机二进制位

伪随机 和 真随机

上面提到了 伪随机 和 真随机,这里的 "真" 和 "伪" 是相对的

伪随机数 是通过算法计算出来,它只具有计算随机性

真随机数来自于系统中各种环境噪音数据,再利用算法混淆,可以认为是完全随机的了,具有真实的随机性和计算随机性

但是,对于一些微型的Linux系统,它的环境噪音很少,而且噪音种类也比较固定,能被猜测到的概率会大大增加,那么它真实的随机性就大打折扣了,这时它产生的随机数的随机性 和 伪随机数已经差不多了

使用哪个随机数生成器

/dev/random/dev/urandom 都是 Linux 上两个随机数生成器,那我们应用中使用哪一个呢,按照怎样的原则去选呢 ?

首先要明确一点,/dev/random/dev/urandom 产生的随机数都是从同一个熵池 ( 主熵池 ) 中提取的,只有当各自的熵池耗尽了,它们的行为才有所不同: /dev/random 阻塞,而 /dev/urandom 没有,但是此时它返回的是用算法计算出来的伪随机数

一般有个规则,/dev/random 产生的随机数质量高,主要用于一些安全方面,而且,它是阻塞的,对于大部分应用来说,这是不能接受的

对于 /dev/urandom ,当熵池计数器足够的时候,产生真随机数,计数不够的时候,产生伪随机数,最重要的是 它不会阻塞,而且,对于绝大多数的应用来说,伪随机数也能很好的满足需求了

小结

本文主要介绍了 Linux 下 /dev/random 和 /dev/urandom 两种随机数生成器的原理以及区别,关于它们更细节的知识请自行查阅 man 文档 或 参考下面的链接

posted @ 2021-11-23 16:30  Linux开发那些事儿  阅读(3353)  评论(2编辑  收藏  举报