If you're asking why openssl rand
or RAND_bytes()
do not simply regurgitate /dev/random
or /dev/urandom
, it's because their function is to serve only as a PRNG, and they do exactly that:
The rand
command outputs num pseudo-random bytes after seeding the random number generator once.
A correctly compiled and operating OpenSSL will read 32 bytes from /dev/urandom
where available (and unless a hardware engine is specified instead), and use (some or all of) this to seed a PRNG. You can confirm if random
or urandom
are read with strace
on a *nix system with:
$ strace -xe trace=file,read,write,close openssl rand 10
[...]
open("/dev/urandom", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 3
read(3, "\x26\x20\xfc\x61\x59\x81\xc9\x4d\xe5\x27\xab\xc2\x72\xb1"..., 32) = 32
close(3) = 0
As to why that is so, as a software library, OpenSSL cannot generate truly random numbers directly. The choices are to use a cryptographically secure PRNG with a good random seed (i.e. with OS harvested data from effectively random hardware events); or use a real hardware RNG. The Hardware section of the wiki explains how to do the latter, including how to access on-chip (Intel's RDRAND) RNG using the "engine" capability. Thomas Pornin's excellent answer here explains why a (correctly seeded, cryptographically-secure) PRNG is sufficient for most purposes: Evaluating the entropy gathering in a PRNG
If you want to be in charge of feeding random data to OpenSSL in a configurable way then using an EGD-style socket might be the easiest option. If you want to feed random numbers directly through the OpenSSL API, an engine is the "best" option (though you can cheat a little, example here)
I believe OpenSSL uses its own PRNG algorithm, unless you have FIPS enabled.
OpenSSL absolutely does use /dev/random
when available: an excerpt from one of the answers in the FAQ:
All OpenSSL versions try to use /dev/urandom by default; starting with version 0.9.7, OpenSSL also tries /dev/random if /dev/urandom is not available.
and the wiki page you reference:
Initialization
OpenSSL will attempt to seed the random number generator automatically upon instantiation by calling RAND_poll. RAND_poll seeds the random number generator using a system-specific entropy source, which is /dev/urandom on UNIX-like operating systems, and is a combination of CryptGenRandom and other sources of entropy on Windows.
You also asked about whether this is "seeding a PRNG from a PRNG", it depends on how strictly you define a PRNG. A defining property of a PRNG is that it is deterministic, a PRNG has a "secret" starting point (defined by the seed), thereafter it is predictable (if you know that secret and the current iteration or, by extension the internal state). While a normal Linux random
is clearly not a true "unobservable" or quantum RNG, it's not quite a normal PRNG either since its output quite quickly diverges from the deterministic values the initial seeding would result in. Conjecture aside, I think the contemporary term is a "PRNG with input", see this PDF paper, so a qualified "yes".
Since 0.9.7 OpenSSL defaults (DEVRANDOM
define) to using in order: /dev/urandom
, /dev/random
, /dev/srandom
(with 10ms non-blocking reads) and advises:
/* Use a random entropy pool device. Linux, FreeBSD and OpenBSD
* have this. Use /dev/urandom if you can as /dev/random may block
* if it runs out of random entries. */
(OpenSSL-1.0.1e crypt/rand/rand_unix.c
)
The contents of "random
" should be used sparingly because it comes with some implied quality and is rate-limited. While urandom
won't block, it's implied that its quality degrades with use. (At least on Linux, urandom
is different on other platforms.)
Finally, some ancient history... OpenSSL is derived from SSLeay (OpenSSL was born at v0.9.0), and SSLeay (0.1 released April 1995) pre-dates commonly available OS managed (P)RNG. Linux was the first to get a random
device in v1.3.30 in 1994, followed by FreeBSD 2.2 in 1995. The RAND_bytes()
PRNG dates from this time, so it's interesting to see in the documentation
(doc/rand.doc
from 0.5.1b):
First up I will state the things I believe I need for a good RNG.
1) A good hashing algorithm to mix things up and to convert the RNG 'state'
to random numbers.
2) An initial source of random 'state'.
3) The state should be very large. [...snip...]
which is followed by further discussion and a prescient summary:
So of the points raised, only 2 is not addressed, but sources of random data
will always be a problem.
SSLeay first gained /dev/random
support in version 0.5.3 (probably early 1996, change logs are a bit vague). Prior to that the PID, UID, timestamp and AFAICT, whatever was on the stack had to suffice. So RAND_bytes()
was always a PRNG because that's a fast and portable solution. It uses what ever it can scavenge to seed the PRNG to give a useful quantity of random data, including OS provided randomness. When there's a hardware specific alternative to a PRNG, then a crypto engine can provide this functionality.
With regard to the behaviour of -rand
I assume you mean when used with something like "openssl genrsa 2028
". It probably just behaves this way because a moderate but indeterminate amount of random data is required (numbers are generated at random and tested for primality, a pair are needed) and the alternative was never considered useful (roughly 10-40 kiB of truly random data, as an educated guess).