强制 OpenSSL 的 RNG 返回可重复的字节序列 [英] Force OpenSSL's RNGs to return a repeatable byte sequence

查看:27
本文介绍了强制 OpenSSL 的 RNG 返回可重复的字节序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

For unit tests of a cryptographic utility, I would like to be able to force OpenSSL's cryptographic random number generator (both RAND_bytes and RAND_pseudo_bytes) to return predictable, repeatable byte sequences, so that various ciphertexts are in turn predictable and can be baked into test vectors. (All other key material is under my control.)

我知道这完全破坏了安全性.这将仅用于单元测试.

我不能在每次测试之前简单地用一个固定的种子调用 RAND_seed,因为(看起来)RNG 会自动从 /dev/urandom 自动播种自己,无论我想要它与否,无论如何RAND_seed 不会重置 RNG,它只会将种子添加到熵池中.

I cannot simply call RAND_seed with a fixed seed before each test, because (it appears) the RNG automatically seeds itself from /dev/urandom whether I want it to or not, and anyway RAND_seed doesn't reset the RNG, it only adds the seed to the entropy pool.

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

Is there any way to do this? (In extremis, it looks like I could write my own PRNG engine, but I'd like to think there's a simpler option.)

推荐答案

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

You can force the FIPS ANSI X9.31 RNG into a test mode at runtime, but not the SSLeay RNG (the default). If you recompile OpenSSL with -DPREDICT, the default RNG will output a predictable sequence of numbers, but that's not very convenient.

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

The RAND_pseudo_bytes function generates a predictable series of numbers, meaning it does not add entropy to itself automatically like RAND_bytes. But like you noticed it's only possible to add entropy to the seed, not provide the seed explicitly, so between runs of the program you'll get different numbers. Also not helpful.

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

But writing your own predictable RNG engine is not difficult. In fact, I'll take you through it by making a rand engine with stdlib's rand() at its core:

#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
", rnum[0], rnum[1], rnum[2], rnum[3], rnum[4]);

        return 0;
}

每次运行这个程序时,它都会给 srand() 播种相同的数字,因此每次都会给你相同的随机数序列.

Every time you run this program, it seeds srand() with the same number and therefore gives you the same sequence of random numbers every time.

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$ 

这篇关于强制 OpenSSL 的 RNG 返回可重复的字节序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆