您可以在运行时将FIPS ANSI X9.31 RNG强制进入测试模式,但不能对SSLeay RNG(默认值)进行操作。如果使用
-DPREDICT
重新编译OpenSSL,则默认RNG会输出可预测的数字序列,但这不是很方便。
RAND_pseudo_bytes
函数生成可预测的数字序列,这意味着它不会像
RAND_bytes
那样自动添加熵。但正如您注意到的,只能向种子添加熵,而无法显式提供种子,因此在程序运行之间,您将获得不同的数字。这也没有什么帮助。
但编写自己的可预测RNG引擎并不困难。实际上,我会通过使用stdlib的
rand()
来创建一个rand引擎:
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <openssl/rand.h>
static void stdlib_rand_cleanup() {}
static void stdlib_rand_add(const void *buf, int num, double add_entropy) {}
static int stdlib_rand_status() { return 1; }
static void stdlib_rand_seed(const void *buf, int num)
{
assert(num >= sizeof(unsigned int));
srand( *((unsigned int *) buf) );
}
static int stdlib_rand_bytes(unsigned char *buf, int num)
{
for( int index = 0; index < num; ++index )
{
buf[index] = rand() % 256;
}
return 1;
}
RAND_METHOD stdlib_rand_meth = {
stdlib_rand_seed,
stdlib_rand_bytes,
stdlib_rand_cleanup,
stdlib_rand_add,
stdlib_rand_bytes,
stdlib_rand_status
};
RAND_METHOD *RAND_stdlib() { return &stdlib_rand_meth; }
int main()
{
int test_mode = 1;
if( test_mode )
{
RAND_set_rand_method(RAND_stdlib());
}
unsigned int seed = 0x00beef00;
unsigned int rnum[5];
RAND_seed(&seed, sizeof(seed));
RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum));
printf("%u %u %u %u %u\n", rnum[0], rnum[1], rnum[2], rnum[3], rnum[4]);
return 0;
}
每次运行这个程序,它都使用相同的数字来初始化
srand()
,因此每次都会得到相同的随机数序列。
corruptor:scratch indiv$ g++ rand.cpp -o r -lcrypto -g
corruptor:scratch indiv$ ./r
1547399009 981369121 2368920148 925292993 788088604
corruptor:scratch indiv$ ./r
1547399009 981369121 2368920148 925292993 788088604
corruptor:scratch indiv$