Принудительно заставить RNG openssl возвращать повторяемую последовательность байтов - PullRequest
5 голосов
/ 16 сентября 2011

Для модульных тестов криптографической утилиты я хотел бы иметь возможность заставить криптографический генератор случайных чисел OpenSSL (как RAND_bytes, так и RAND_pseudo_bytes) возвращать предсказуемые, повторяемые последовательности байтов, так что различные шифротексты в свою очередь предсказуемыи может быть запечен в тестовые векторы.(Все остальные ключевые материалы находятся под моим контролем.)

Я знаю, что это полностью подрывает безопасность.Это будет использоваться только для юнит-тестов.

Я не могу просто вызывать RAND_seed с фиксированным начальным числом перед каждым тестом, потому что (кажется), что ГСЧ автоматически заполняется из /dev/urandomхочу ли я этого или нет, и в любом случае RAND_seed не сбрасывает ГСЧ, он только добавляет начальное число в пул энтропии.

Есть ли способ сделать это?(В крайнем случае, похоже, я мог бы написать свой собственный движок PRNG, но я хотел бы подумать, что есть более простой вариант.)

Ответы [ 2 ]

6 голосов
/ 22 сентября 2011

Вы можете принудительно включить RNG FIPS ANSI X9.31 в тестовый режим во время выполнения, но не для SSLeay RNG (по умолчанию).Если вы перекомпилируете OpenSSL с -DPREDICT, RNG по умолчанию выведет предсказуемую последовательность чисел, но это не очень удобно.

Функция RAND_pseudo_bytes генерирует предсказуемую последовательность чисел, то есть не добавляет энтропиик себе автоматически, как RAND_bytes.Но, как вы заметили, можно только добавить энтропию в начальное число, не предоставив начальное в явном виде, поэтому между запусками программы вы получите разные числа.Тоже не полезно.

Но написать свой собственный предсказуемый движок ГСЧ не сложно.На самом деле, я проведу вас через это, сделав рэнд-движок с ядром stdlib 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;
}

Каждый раз, когда вы запускаете эту программу, она запускает 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$ 
1 голос
/ 16 сентября 2011

Напишите обертку вокруг библиотеки.Затем замените его во время теста на ваш собственный макет, который возвращает ваши магические значения.

Помните, что в модульном тесте вы не пытаетесь проверить OpenSSL.Вы пытаетесь проверить свой код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...