Puede forzar el FIPS ANSI X9.31 RNG a un modo de prueba en tiempo de ejecución, pero no al SSLeay RNG (valor predeterminado). Si recompila OpenSSL con -DPREDICT
, el RNG predeterminado generará una secuencia predecible de números, pero eso no es muy conveniente.
La función RAND_pseudo_bytes
genera una serie predecible de números, lo que significa que no agrega automáticamente entropía como RAND_bytes
. Pero como notó, solo es posible agregar entropía a la semilla, no proporcionar la semilla explícitamente, por lo que entre las ejecuciones del programa obtendrá diferentes números. Tampoco es útil.
Pero escribir su propio motor RNG predecible no es difícil. De hecho, te llevaré a través de él al hacer un motor de rand con stdlib de rand()
en su núcleo:
#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;
}
Cada vez que se ejecuta este programa, semillas srand()
con el mismo número y por lo tanto le da la misma secuencia de números aleatorios todo el tiempo.
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$
No necesita un PRNG. Solo necesita una secuencia predecible de valores; incluso un contador servirá. –