RAND_bytes doesn't give the same result from the same seed

5.6k views Asked by At

I'm trying to program custom RSA key pair generation algorithm using OpenSSL. I've used the PKCS5_PBKDF2_HMAC_SHA1 function to generate PRNG seed, so, I've used this seed as RAND_seed input.

Unfortunately every time I call RAND_bytes, with the same seed, I obtain different random numbers, but this isn't the expected behaviour, because as say the answer at How can one securely generate an asymmetric key pair from a short passphrase? the random number generator is deterministic (same seed same output).

Below is the test case. I've declared also constant seed, but the generation is never deterministic.

unsigned int seed = 0x00beef00;
unsigned int rnum[5];
RAND_seed(&seed, sizeof(seed));
RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum));

Where is the error?

2

There are 2 answers

4
infixed On

Openssl's int RAND_bytes(unsigned char *buf, int num); tries to make things as random as it can. That is apparently a feature you don't want, and are instead looking for a repeatable pseudorandom sequence

But Openssl also has

int RAND_pseudo_bytes(unsigned char *buf, int num);

which is probably what you are looking for, the pseudo part, to give you the repeatable sequence.

https://linux.die.net/man/3/rand_pseudo_bytes

Force openssl's RNGs to return a repeatable byte sequence

As an aside, if you are doing RSA, a repeatable random sequence isn't all that good, because what you are looking for are two large primes. Doing a large PRNG number, then testing for prime is probably a bad idea. Half of them will be divisible by 2! :)

If I recall correctly, you need to pick a good starting number, make it odd by ORing with 1, then test for prime, and if it is not, increment by 4 and try again.

Once you find them, you probably will not want to do it again using repeatable PRNG bytes to start your search.

And while I'm pretty sure this is for a learning project, but if all you want is a RSA key pair from openssl check out

https://stackoverflow.com/a/5246045/6047952

2
dbush On

This is not an error. The OpenSSL random number generator does some seeding on its own using good sources of randomness.

So using the same seed value in RAND_seed does not guarantee the same sequence of random numbers. This is a Good Thing because it makes them less predictable and therefore more secure.

From the man page for RAND_seed:

    #include <openssl/rand.h>

    void RAND_seed(const void *buf, int num);

    void RAND_add(const void *buf, int num, double entropy);

    int  RAND_status(void);

    int  RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam);
    void RAND_screen(void);

RAND_add() mixes the num bytes at buf into the PRNG state. Thus, if the data at buf are unpredictable to an adversary, this increases the uncertainty about the state and makes the PRNG output less predictable. Suitable input comes from user interaction (random key presses, mouse movements) and certain hardware events. The entropy argument is (the lower bound of) an estimate of how much randomness is contained in buf, measured in bytes. Details about sources of randomness and how to estimate their entropy can be found in the literature, e.g. RFC 1750.

RAND_add() may be called with sensitive data such as user entered passwords. The seed values cannot be recovered from the PRNG output.

OpenSSL makes sure that the PRNG state is unique for each thread. On systems that provide "/dev/urandom", the randomness device is used to seed the PRNG transparently. However, on all other systems, the application is responsible for seeding the PRNG by calling RAND_add(), RAND_egd(3) or RAND_load_file(3).

RAND_seed() is equivalent to RAND_add() when num == entropy.

So if your system has /dev/urandom, it will be used as the initial seed for the PRNG.