• Jason A. Donenfeld's avatar
    random: use simpler fast key erasure flow on per-cpu keys · 186873c5
    Jason A. Donenfeld authored
    Rather than the clunky NUMA full ChaCha state system we had prior, this
    commit is closer to the original "fast key erasure RNG" proposal from
    <https://blog.cr.yp.to/20170723-random.html>, by simply treating ChaCha
    keys on a per-cpu basis.
    
    All entropy is extracted to a base crng key of 32 bytes. This base crng
    has a birthdate and a generation counter. When we go to take bytes from
    the crng, we first check if the birthdate is too old; if it is, we
    reseed per usual. Then we start working on a per-cpu crng.
    
    This per-cpu crng makes sure that it has the same generation counter as
    the base crng. If it doesn't, it does fast key erasure with the base
    crng key and uses the output as its new per-cpu key, and then updates
    its local generation counter. Then, using this per-cpu state, we do
    ordinary fast key erasure. Half of this first block is used to overwrite
    the per-cpu crng key for the next call -- this is the fast key erasure
    RNG idea -- and the other half, along with the ChaCha state, is returned
    to the caller. If the caller desires more than this remaining half, it
    can generate more ChaCha blocks, unlocked, using the now detached ChaCha
    state that was just returned. Crypto-wise, this is more or less what we
    were doing before, but this simply makes it more explicit and ensures
    that we always have backtrack protection by not playing games with a
    shared block counter.
    
    The flow looks like this:
    
    ──extract()──► base_crng.key ◄──memcpy()───┐
                       │                       │
                       └──chacha()──────┬─► new_base_key
                                        └─► crngs[n].key ◄──memcpy()───┐
                                                  │                    │
                                                  └──chacha()───┬─► new_key
                                                                └─► random_bytes
                                                                          │
                                                                          └────►
    
    There are a few hairy details around early init. Just as was done
    before, prior to having gathered enough entropy, crng_fast_load() and
    crng_slow_load() dump bytes directly into the base crng, and when we go
    to take bytes from the crng, in that case, we're doing fast key erasure
    with the base crng rather than the fast unlocked per-cpu crngs. This is
    fine as that's only the state of affairs during very early boot; once
    the crng initializes we never use these paths again.
    
    In the process of all this, the APIs into the crng become a bit simpler:
    we have get_random_bytes(buf, len) and get_random_bytes_user(buf, len),
    which both do what you'd expect. All of the details of fast key erasure
    and per-cpu selection happen only in a very short critical section of
    crng_make_state(), which selects the right per-cpu key, does the fast
    key erasure, and returns a local state to the caller's stack. So, we no
    longer have a need for a separate backtrack function, as this happens
    all at once here. The API then allows us to extend backtrack protection
    to batched entropy without really having to do much at all.
    
    The result is a bit simpler than before and has fewer foot guns. The
    init time state machine also gets a lot simpler as we don't need to wait
    for workqueues to come online and do deferred work. And the multi-core
    performance should be increased significantly, by virtue of having hardly
    any locking on the fast path.
    
    Cc: Theodore Ts'o <tytso@mit.edu>
    Cc: Dominik Brodowski <linux@dominikbrodowski.net>
    Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Reviewed-by: default avatarJann Horn <jannh@google.com>
    Reviewed-by: default avatarEric Biggers <ebiggers@google.com>
    Signed-off-by: default avatarJason A. Donenfeld <Jason@zx2c4.com>
    186873c5
random.c 50.6 KB