openssl生成随机数的源码位于crypto/rand目录下。rand.h定义了许多与随机数生成相关的函数。openssl通过使用摘要算法来生成随机数,可用的摘要算法有:sha1、md5、mdc2和md2。具体采用那种摘要算法在crypto/rand_lcl.h中由宏来控制。Openssl维护一个内部随机状态数据(md_rand.c中定义的全局变量state和md),通过对这些内部数据计算摘要来生成随机数。
Openssl随机数相关的数据结构如下,定义在rand.h中:
struct rand_meth_st
{
void (*seed)(const void *buf, int num);
int (*bytes)(unsigned char *buf, int num);
void (*cleanup)(void);
void (*add)(const void *buf, int num, double entropy);
int (*pseudorand)(unsigned char *buf, int num);
int (*status)(void);
};
本结构主要定义了各种回调函数,如果用户需要实现自己的随机数生成函数,他需要实现本结构中的各个函数。Openssl给出了一个默认的基于摘要的rand_meth实现(crypto/md_rand.c)。各项意义如下:
seed:种子函数,为了让openssl内部维护的随机数据更加无序,可使用本函数。buf为用户输入的随机数地址,num为其字节数。Openssl将用户提供的buf中的随机内容与其内部随机数据进行摘要计算,更新其内部随机数据。本函数无输出;
bytes:生成随机数,openssl根据内部维护的随机数状态来生成结果。buf用于存放生成的随机数。num为输入参数,用来指明生成随机数的字节长度;
cleanup:清除函数,本函数将内部维护的随机数据清除;
add:与seed类似,也是为了让openssl内部随机数据更加无序,其中entropy(信息熵)可以看作用户本次加入的随机数的个数。Openssl默认的随机数熵为32字节,在rand_lcl.h中由ENTROPY_NEEDED定义。Openssl给出随机数之前,用户提供的所有的随机种子数之和必须达到32字节。在openssl实现的md_rand中,即使用户不调用种子函数来直接生成随机数,openssl也会调用RAND_poll函数来完成该操作。
pseudorand:本函数与bytes类似也是来生成随机数。
status:查看熵值是否达到预定值,openssl中为32字节,如果达到则返回1,否则返回0。在openssl实现的md_rand中该函数会调用RAND_poll函数来使熵值合格。如果本函数返回0,则说明此时用户不应生成随机数,需要调用seed和add函数来添加熵值。
cypto/rand目录下的主要源码有:
1) md_rand.c
它实现了基于摘要的随机数生成。
2) rand_lib.c
该文件中的源码简单调用了rand_meth中的回调函数。
3) rand_win.c/rand_unix.c/rand_os2.c等
这些源码主要提供了平台相关的RAND_poll函数实现和其他系统特有函数的实现。比如rand_win.c实现了RAND_screen函数,用户根据屏幕来设置随机数种子。
4) randfile.c
用于从随机文件中加载种子、生成随机数文件以及获取随机文件名。比如默认的随机数文件为.rnd文件,如果找不到该文件,openbsd可能会返回/dev/arandom。