0%

伪随机数生成 Lab

一.实验目的

生成随机数是安全软件中非常常见的任务。在许多情况下,加密密钥不是由用户提供的,而是在软件内部生成的。它们的随机性非常重要。否则,攻击者可以预测加密密钥,从而达到破坏加密目的。许多开发人员从其先前的经验中知道如何生成随机数(例如用于蒙特卡洛模拟),因此他们使用类似的方法生成用于安全目的的随机数。不幸的是,随机数序列对于蒙特卡洛模拟可能是好的,但对于加密密钥则可能是不好的。开发人员需要知道如何生成安全的随机数,否则就会犯错。在一些著名的产品(包括Netscape和Kerberos )中也犯过类似的错误。

在本实验中,学生将学习为什么典型的随机数生成方法不适用于生成秘密(例如加密密钥)。进一步学习生成用于安全目的的伪随机数的标准方法。本实验涵盖以下主题:

1. 伪随机数生成

2. 随机数生成中的错误

3. 加密密钥生成

4. 设备文件/dev/random 和/dev/urandom

二.实验步骤与结果

2.1 Task 1:用错误的方式生成加密密钥

要生成一个好的伪随机数,我们需要从一些随机的东西开始。否则,结果会是可预测的。库函数time() 以从纪元1970-01-01 00:00:00 +0000 (UTC) 起的秒数的形式返回当前时间。运行上面的代码,并描述你的观察结果。然后,注释掉第À 行,再次运行该程序,并描述你观察到的结果。使用在两种情况下观察到的结果来解释代码中srand() 和time() 函数的用途。

注释前如上图所示,每次生成的随机数不同。

注释掉后如上图所示,每次生成的随机数相同

解释:

srand函数用于给随机数生成器根据当前系统时间设定种子,而将该函数注释掉后,会默认使用随机数种子0,因此会产生两种不同的观察结果。

2.2 Task 2: 猜测密钥

给定以AES—CBC模式加密的明文,密文以及初始IV如下:

编写一个程序用于尝试所有可能的密钥。密钥生成方式由TASK1给出。

思路:

首先利用task1中所给出的代码进行改写,根据所给出时间的及其前两个小时的时间种子来生成128bit长度的密钥,然后再编写脚本来遍历所生成的密钥,利用AES进行加密明文,如过加密后的密文与给出的密文相同,则得到正确的密钥。

首先查看时间如下:

利用时间种子进行生成密钥,并保存在文件中。

代码如下图:

生成结果如下,可以观察到生成了16bytes长的密钥如下:

编写python脚本如下:

执行脚本即可得到正确的密钥如下图:

2.3 Task 3: 测量内核的熵

随机性使用熵来度量,这与信息论中熵的含义不同。在这里,熵仅仅意味着系统当前有多少bit 的随机数。你可以使用下面的命令找出在当前时刻内核的熵是多少。

watch 可以周期性地执行一个程序。我们使用watch 运行上面的命令来监控熵的变化。下面的命令每0.1 秒就执行一次cat 程序。请执行上面的命令。在它运行时,移动你的鼠标,点击鼠标,输入什么东西,读取一个大文件,访问一个网站。哪些活动会显著地使熵变大?请在实验报告中描述你的发现。

移动鼠标会发现,增长很慢,移动一次即可增长1

输入字符,输入一个字符熵增长1

阅读文件,这里阅读系统日志,发现利用less阅读一次熵增长

访问网站,熵并不会自动增长,其增长取决于鼠标的点击移动以及字符的输入。

2.4 任务4: 从/dev/random 中获取伪随机数

Linux 将从物理资源收集的随机数据存储到一个随机池中,然后使用两个设备将随机源转换为伪随机数。这两个设备是/dev/random 和/dev/urandom 。它们有不同的行为。/dev/random 设备是阻塞设备。即,每当该设备给出随机数时,随机池的熵将减小。当熵达到零时,/dev/random 将阻塞,直到获得足够的随机性为止。

让我们设计一个实验来观察/dev/random 设备的行为。我们将使用cat 命令持续从/dev/random 中读取伪随机数。我们将输出通过管道传递到hexdump 以便获得良好的输出。

请运行上面的命令,同时使用watch 命令来监视熵。如果不移动鼠标,也不键入任何内容,将会发生什么。然后,随机移动鼠标,看看是否可以观察到任何差异。请描述并解释你观察到的现象。

如上图所示,如果没有操作,间隔一到二分钟后,会自动生成一行随机数,如果随机移动鼠标生成新的一行随机数的时间间隔变小。

解释如下:

为了保证随机数的质量,/dev/random 只能返回熵池当前最大可用的随机二进制位,当请求超过这个值,就会阻塞,直到熵池中有足够的随机二进制位。而移动鼠标可以增加当前的熵,因而其生成新一行随机数的时间间隔变小。

问题: 假设一个服务器使用/dev/random 与客户端生成随机会话密钥。请描述你将如何对这样的一个服务器发起拒绝服务(DoS)攻击。

回答:不断向服务器发送请求使其生成返回熵池中最大可用随机二进制位,直至其阻塞。

2.5 任务5: 从/dev/urandom 获取随机数

Linux 提供了另一种方式,可以通过/dev/urandom 设备访问随机池。/dev/random 和/dev/urandom都可以使用随机池中的数据生成伪随机数。当熵不足时,/dev/random 将会暂停,而/dev/urandom 会继续生成新的数。将随机池中的数据视作“种子”,我们可以使用种子想生成多少随机数就生成多少。

让我们来看看/dev/urandom 的行为。我们再次使用cat 从设备中获取伪随机数。请运行下面的命令,描述移动鼠标是否会影响结果。

如上图所示,urandom会不断产生新的随机数,其产生速度很快且没有任何停顿,移动鼠标并不会影响结果。

让我们测量随机数的质量。我们可以使用一个名为ent 的工具,该工具已经安装在我们的虚拟机中。根据其手册所言:“ent 对存储在文件中的字节序列进行各种测试,并报告这些测试的结果。该程序对于评估加密和统计采样应用程序,压缩算法以及其他文件信息密度受关注的应用程序的伪随机数生成器很有用”。让我们首先从/dev/urandom 生成1 MB 的伪随机数,并将其保存在文件中。然后,在该文件上运行ent。请描述你的结果,并分析随机数的质量是否良好

运行结果如下图所示:

分析随机数质量:

可以观察到其熵接近8比特,可以得知其信息很密集,随机性好。

数据字节的算数平均值接近于127.5,蒙特卡洛值接近Π,行相关系数接近于0,因此可以推断由urandom所产生的随机数的随机性较好。

修改实验手册中的代码片段来生成一个256 bit 的加密密钥。请编译并运行你的代码,输出这些数并将屏幕截图放在报告里。

修改代码如下图:

运行结果如下: