Ilya Maximets <[email protected]> writes:

> On 10/28/26 8:14 PM, Aaron Conole wrote:
>> Until now, utilities wishing access to a quality source of
>> cryptographically secure random numbers would have to either
>> forego security and just use the xorshift, or use one of a
>> few very slow entropy options like get_entropy_or_die or
>> OpenSSL's RAND_bytes() calls.  Both of these are quality
>> tested mechanisms, but the drawback is a very long time to
>> execute (measured 10m iterations of rand_bytes taking
>> roughly 5.14s to complete).
>> 
>> This change adds a ChaCha20 based CSPRNG, which is known
>> to be a high quality CSPRNG.  The benefits are very fast
>> execution time (the same 10m iterations only take 0.059s
>> vs. the PRNG taking 0.018s).
>> 
>> The following references can help with understanding the
>> implementation:
>>  * RFC 8439, "ChaCha20 and Poly1305 for IETF Protocols"
>>  * libevent/arc4random.c, "Arc4 random number generator for OpenBSD."
>>  * glibc/stdlib/arc4random.c, "Psuedo random number generator"
>>  * Ben Tasker, "Writing (and backdooring) a ChaCha20 based CSPRNG"
>> 
>> Assisted-by: LLM (claude, opencode, sonnet, opus, qwen3.8)
>> Signed-off-by: Aaron Conole <[email protected]>
>> ---
>> v2->v3:
>>   * Update the verbiage around the implementations origins
>>   * Still exists the possiblity to abort on reseed
>>   * Fixed the CHACHA_K_INPUT comment
>>   * Fixed the chacha_sigma constant definition + comment
>>   * Documented maximum length in csprng_random_bytes
>>   * Introduce ovs_memzero that will clear memory without eliding
>>     the operations
>>   * Zero out the chacha20_block
>
> [...]
>
>> +struct csprng {
>> +    uint32_t state[16];             /* ChaCha20 state:
>> +                                     * constant|key|counter|nonce. */
>> +    uint8_t buf[CSPRNG_BUFSZ];      /* Buffered keystream. */
>> +    size_t pos;                     /* Next unused byte in 'buf'. */
>> +    size_t served;                  /* Bytes served since last reseed. */
>> +    int initialized;
>> +};
>> +
>> +/* ChaCha20 constant: "expand 32-byte k".  Must be at least 16
>> bytes + NUL. */
>> +static const uint8_t chacha_sigma[] = "expand 32-byte k";
>> +
>> +/* Current random state. */
>> +DEFINE_STATIC_PER_THREAD_DATA(struct csprng, cs_state, { .initialized = 0 
>> });
>
> LLMs complain that this state is preserved on fork.  It's probably not a big
> deal since there should be no cases where this code would be used before 
> forking
> today, but maybe a bit of a trap.  Maybe we should make xfork_at()
> call a special
> function that clears the state if it was initialized before?

It's a weird complaint.  Honestly, there isn't much that we can do if
someone does a fork() unless we explicitly are only calling forks from
our library.  But a code that can somehow do a fork() from a called
library will still completely bypass any preventing measures we do here.

The real way to do it safely is to use xmalloc() for the per-thread
allocation and madvise(region, MADV_WIPEONFORK), I think.  Then even if
a library we link do does a fork(), the pages are guaranteed to be
wiped.

> It's not the only place where we can fork, but it may be better to convert 
> other
> place into xfork if needed in the future.
>
> WDYT?
>
> Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to