[Cryptography] Fast-key-erasure RNG and fork()ing

Yann Ylavic ylavic.dev at gmail.com
Thu Jun 28 18:46:46 EDT 2018

On Wed, Jun 27, 2018 at 8:29 PM, Florian Weimer <fw at deneb.enyo.de> wrote:
> * Yann Ylavic:
>> I wonder how I'd best handle fork()ed processes, given that with the
>> above design the forked key is the one that should produce the next
>> keystream, and obviously the parent and child processes must not use
>> the same one.
> You can use two counters, one in a MAP_SHARED page, and one in a
> MAP_PRIVATE page.  Increment them before and after each access to
> random data, under a process-private lock, and compare if they are
> still the same.  You have to reseed if the counters diverge.
> An implementation of this approach is part of this patch (still under
> review, LGPLv2.1+ license, so be careful if that matters to you):
> <https://sourceware.org/ml/libc-alpha/2018-06/msg00674.html>

Indeed, nice feature and design.

Actually I'm working on this PRNG ([1]) for the Apache Runtime library
(APR, Apache license v2), besides the portability (P stands for that
in A*P*R) and license issues, I didn't intend to go that far and
"catch" fork()s for now.

The lib provides a wrapper for fork() which pretty much does ([1]):
  pid = fork()
  crypto_prng_after_fork(pid == 0) /* act differently for parent and child */

and the user is supposed to call it to fork a new process.

So my question was more about the correct rekeying in _after_fork(),
so that parent and child process hide their state from each other.
After some work/out-of-list discussions I think I got it right by
rekeying appropriately, solely based on the keystream(s) ([3]), and
getting rid of the SHA256(getpid()) xor stuff.

This PRNG for now is not any-fork() proof, it's meant to run either in
it's own (hardened) process with a named socket/pipe interface, or in
a "trusted" environment with wrapped fork()s and no arbitrary code run
The design at least ensures that if the process crashes, there is no
key/state material to recover the random bytes provided so far.
It's also fast (faster than getrandom() for instance, I didn't test
arc4random_buf()), but the comparison is probably not fair...
Mainly, for a lib which supports quite some platforms, it's
cryptographically safe (supposedly) and never blocks besides the
initial 32 bytes entropy gathered from the system. Not all platforms
provide get/arc4-random() unfortunately, while "/dev/urandom" never
blocks but doesn't garanty good randoms either (w/o enough entropy,
how could it), not to talk about mostly unusable "/dev/random" for
modern needs of randoms.

Anyway, thanks for the ideas and pointers, I'm now going to care of
any-fork() in a portable way (wish me good luck I guess, at least I
can do it right for modern systems it seems).


[1] https://github.com/apache/apr/blob/trunk/crypto/apr_crypto_prng.c
[2] https://github.com/apache/apr/blob/trunk/threadproc/unix/proc.c#L220
[3] https://github.com/apache/apr/blob/trunk/crypto/apr_crypto_prng.c#L652

More information about the cryptography mailing list