强制openssl的RNG返回可重复的字节序列

zwo*_*wol 5 unit-testing openssl

对于加密实用程序的单元测试,我希望能够强制OpenSSL的加密随机数生成器(两者RAND_bytes和两者RAND_pseudo_bytes)返回可预测的,可重复的字节序列,以便各种密文可以预测并且可以烘焙到测试向量中.(所有其他关键材料都在我的控制之下.)

我知道这完全打败了安全.这仅用于单元测试.

我不能简单地RAND_seed在每次测试之前使用固定的种子进行调用,因为(看起来)RNG会根据/dev/urandom我是否需要它来自动播种,并且无论如何RAND_seed都不会重置 RNG,它只会将种子添加到熵池中.

有没有办法做到这一点?(在极端情况下,看起来我可以编写自己的PRNG引擎,但我想有一个更简单的选择.)

ind*_*div 6

您可以在运行时强制FIPS ANSI X9.31 RNG进入测试模式,但不能强制使用SSLeay RNG(默认值).如果你重新编译OpenSSL -DPREDICT,默认的RNG将输出一个可预测的数字序列,但这不是很方便.

RAND_pseudo_bytes函数生成一系列可预测的数字,这意味着它不会自动添加熵RAND_bytes.但是就像你注意到只能将熵添加到种子中,不能明确提供种子,所以在程序运行之间你会得到不同的数字.也没有帮助.

但是编写自己的可预测RNG引擎并不困难.事实上,我将通过制作一个以stdlib rand()为核心的rand引擎来引导你完成它:

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <openssl/rand.h>

// These don't need to do anything if you don't have anything for them to do.
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; }

// Seed the RNG.  srand() takes an unsigned int, so we just use the first
// sizeof(unsigned int) bytes in the buffer to seed the RNG.
static void stdlib_rand_seed(const void *buf, int num)
{
        assert(num >= sizeof(unsigned int));
        srand( *((unsigned int *) buf) );
}

// Fill the buffer with random bytes.  For each byte in the buffer, we generate
// a random number and clamp it to the range of a byte, 0-255.
static int stdlib_rand_bytes(unsigned char *buf, int num)
{
        for( int index = 0; index < num; ++index )
        {
                buf[index] = rand() % 256;
        }
        return 1;
}

// Create the table that will link OpenSSL's rand API to our functions.
RAND_METHOD stdlib_rand_meth = {
        stdlib_rand_seed,
        stdlib_rand_bytes,
        stdlib_rand_cleanup,
        stdlib_rand_add,
        stdlib_rand_bytes,
        stdlib_rand_status
};

// This is a public-scope accessor method for our table.
RAND_METHOD *RAND_stdlib() { return &stdlib_rand_meth; }

int main()
{
        // If we're in test mode, tell OpenSSL to use our special RNG.  If we
        // don't call this function, OpenSSL uses the SSLeay RNG.
        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;
}
Run Code Online (Sandbox Code Playgroud)

每次运行此程序时,它都会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$ 
Run Code Online (Sandbox Code Playgroud)