[Cryptography] OpenSSL CSPRNG work

Florian Weimer fw at deneb.enyo.de
Sun Jul 2 04:36:57 EDT 2017


> "Salz, Rich" <rsalz at akamai.com> writes:
>
>> We're starting to work on a new CSPRNG for OpenSSL release 1.1.1 (the
>> main point of that release is TLS 1.3, so we think it will have a lot
>> of uptake).
>
> Have you read "Cryptographic Right Answers" from Thomas Ptacek, who
> actually knows what he is talking about?
>
> https://gist.github.com/tqbf/be58d2d39690c3b366ad
>
>     Use /dev/urandom.
>
>     Avoid: userspace random number generators, havaged, prngd, egd,
>     /dev/random
>
> Why on earth would you put something as critical as random number
> generation into some complex userspace monstrosity?

For glibc, we are also considering adding an implementation of
arc4random to an upcoming release.  The consensus view is that we
cannot use /dev/urandom because it may not be available in chroots.
We support kernels older than 3.17/3.18, so we cannot assume the
presence of the getrandom system call.  And getrandom cannot obtain
randomness if the kernel pool is not initialized (d'oh).  We cannot
keep open a file descriptor to /dev/urandom, so every call would have
to do open/read/close system calls, whose performance impact would
drive away some users.

My hope is to create something that it is reasonable fast so that
using arc4random is a no-brainer, and you'd something else only if you
need a predictable stream of random bits.  It also has to work in case
the kernel pool hasn't been initialized yet, otherwise applications
will switch back to /dev/urandom because it won't block booting.

I'm leaning towards AES-128 in CTR mode with a per-process key, a
global counter, and per-thread counters and output blocks (so around
20 bytes of TLS storage, instead of >176 bytes if we stored an AES key
schedule for every thread).  We'd probably put the per-process key in
non-dumpable memory.  Fork safety is somewhat easier for us than for
others because we can directly invalidate the per-process key from the
fork implementation.  (Clone safety is more complicated.)  Seeding is
still tricky, of course.  We would use the getrandom system call if
available, otherwise fall back to /dev/urandom and then to AT_RANDOM
(directly to AT_RANDOM if the kernel pool is not seeded; we'd then try
to re-seed from getrandom on every arc4random call in that case).
Proper reseeding after fork will be complicated if getrandom is not
available; we'll probably do something theoretically unsound in that
case (and tell people to use a fixed kernel if they dislike this), or
use a MAP_SHARED mapping to maintain counters shared across processes.

This implementation is unlikely to pass certification.  Some auditors
do not allow the use of /dev/urandom to seed another generator.  I
don't know yet if we can just prentend that our arc4random
implementation is not cryptographically secure, and thereby game the
auditing process.  I expect that anyone who uses actual cryptography
uses a cryptographic library which comes with its own CSPRNG, so this
shouldn't be a problem in practice as along as our arc4random provides
an unpredictable stream of bits, even if it is not certified to do so.


More information about the cryptography mailing list