摘要:本文档对OpenSSL使用的随机数进行研究分析,主要涉及OpenSSL v0.9.8a的随机数发生器以及其在Windows系统下的熵源采集情况。
关键词:OpenSSL,密码模块,随机数发生器,密码算法,杂凑算法,熵。
1. 概况
1.1 OpenSSL随机数发生器概况
OpenSSL不同版本使用的随机数发生器不太相同,主要差别在于:
- 非FIPS版本:默认使用OpenSSL内部集成的一款基于HASH算法(默认为SHA1)的随机数发生器;熵源则根据不同的系统有不同的生成方式。
- FIPS版本:使用NIST SP 800-90A的三种随机数发生器,熵源由调用者通过回调函数的方式从外部提供。
非FIPS版本的熵源,根据不同的系统有不同的生成方式,
- Windows系统见.\crypto\rand\rand_win.c文件。
- 低版本的OpenSSL使用大量系统信息作为熵(本文研究重点)。
- 但高版本的则依赖于Windows系统提供的随机数,在Windows 7或更高版本中使用BCrypt代替了CryptoAPI。
- 其他系统的熵源生成方式均可见.\crypto\rand\文件夹。Linux系统使用系统提供的熵源,同样不同大版本使用的熵源差异较大。
下表是OpenSSL几个不同版本使用的随机数发生器的概况。
表1 OpenSSL不同版本使用的随机数发生器概况表
版本 | 随机数发生器 | Windows下熵源 |
OpenSSL 0.9.8a | 自己定义一套随机数发生器 见.\crypto\rand\md_rand.c | 使用大量系统信息 |
OpenSSL 1.1.0 | 同上 | 仅使用Windows提供的随机数API,不再使用大量的系统信息。在Windows 7或更高版本中使用BCrypt代替了CryptoAPI。 |
OpenSSL FIPS 2.0.11 | NIST SP 800-90A的三种随机数发生器 见.\ fips\rand\目录 | 外部提供 |
本文研究OpenSSL 0.9.8a的随机数发生器以及熵源的详情。
OpenSSL在Linux系统下使用的熵源可参见rand_unix.c文件。
OpenSSL FIPS 2.0.11使用的NIST SP 800-90A的三种随机数发生器参见《NIST SP 800-90系列(随机数发生器)笔记》。
1.2 OpenSSL 0.9.8a的随机数发生器概述
内部默认的随机数发生器代码参见.\crypto\rand\md_rand.c文件,这里提供了随机数发生器的状态信息以及一系列的调用函数
- ssleay_rand_seed 添加种子
- ssleay_rand_bytes 产生随机数据
- ssleay_rand_cleanup 置零
- ssleay_rand_add 添加信息
- ssleay_rand_pseudo_bytes 产生伪随机数据
- ssleay_rand_status 获取状态信息
熵源
- RAND_poll 不同版本使用不同的熵源产生方式
2. 随机数发生器内部状态
代码参见.\crypto\rand\md_rand.c文件
随机数发生器的内部状态定义为全局变量(变量名与文件中描述对应),即下表的数据均为static型。
STATE_SIZE 1023
MD_DIGEST_LENGTH 默认使用SHA1算法,所以为20
ENTROPY_NEEDED 所需的熵值,单位字节,值为32
表2随机数发生器内部状态
数据 | 长度 | 类型 | 含义 |
state | STATE_SIZE+ MD_DIGEST_LENGTH字节 | BYTE | 内部状态数据,环形缓冲区。 |
state_num | 4字节 | int | 内部状态实际有效字节数 state_index <= state_num <= STATE_SIZE |
state_index | 4字节 | int | 缓冲区偏移量(当前应处理的内部状态位置) |
md | MD_DIGEST_LENGTH字节 | BYTE | 上一次添加种子(即rand_add)处理得到的摘要值 |
md_count[0] | 4字节 | long | 随机数生成函数rand_bytes的调用次数 |
md_count[1] | 4字节 | long | 记录添加种子函数rand_add送入种子的累积分块数,每次送入的分块数是 向上取整(种子长度/分块长度), |
entropy | 8字节 | double | 熵值,单位字节。 |
initialized | 1比特 | BOOL | 是否初始化 |