È possibile forzare FIPS ANSI X9.31 RNG in una modalità di test in fase di esecuzione, ma non in SSLeay RNG (impostazione predefinita). Se si ricompila OpenSSL con -DPREDICT
, l'RNG predefinito genererà una sequenza prevedibile di numeri, ma non è molto conveniente.
La funzione RAND_pseudo_bytes
genera una serie di numeri prevedibili, il che significa che non aggiunge automaticamente entropia come RAND_bytes
. Ma come hai notato è possibile solo aggiungere entropia al seme, non fornire esplicitamente il seme, quindi tra le esecuzioni del programma otterrai numeri diversi. Inoltre non utile.
Ma scrivere il proprio motore RNG prevedibile non è difficile. In realtà, io ti porto attraverso di essa facendo un motore di rand con stdlib di rand()
al suo interno:
#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;
}
Ogni volta che si esegue questo programma, semi srand()
con lo stesso numero e quindi si dà la stessa sequenza di numeri casuali ogni volta.
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$
Non è necessario un PRNG. Hai solo bisogno di un flusso prevedibile di valori; anche un contatore farà. –