-
-
Notifications
You must be signed in to change notification settings - Fork 486
Description
Status: proposal to allow hardware-dependent generators and replace HC128 with a faster variant of ChaCha (start reading here).
This topic comes up quite a bit from various angles; I think it's time to get some ideas down about the future of thread_rng (regarding the 0.6 release or later).
I see the following potential uses for thread_rng:
- convenient random numbers in small games and simulations
- use in randomised algorithms
- as a source of secret data for various cryptographic applications
Also, I think it's worth mentioning where we do not expect thread_rng to be used:
- anywhere reproducibility is required
- complex simulations and games, due to above point, and also since
thread_rngmay not be the fastest option - where security is very important
And an important note on security: we should aim to provide a secure source of random data, but ultimately it is up to users to decide how much they trust our implementation and what their risks are. thread_rng does not have the simplest code to review and is currently young and subject to further change. Also we may or may not implement forward secrecy (backtracking resistance), and for ultimate security solutions using no local state may be preferred.
Our current implementation of thread_rng tries to satisfy the above with a fast, secure PRNG, but at the cost of high memory usage and initialisation time per thread. For applications with a low number of long-running threads this is reasonable, but for many worker threads may not be ideal.
There are two ways we can let users influence the implementation:
- via feature flags
- at the call site (pass parameters to
thread_rngor call a different function)
Feature flags allow configuration on a per-application basis, e.g.
- prefer low-memory-usage / fast initialisation over generation performance
- disable entirely (i.e. panic on usage)
- require forward secrecy
- remove security requirements (??)
The last two options sound very risky to me — should we ask distributors and end-users to reason about the security of whole applications? It is quite possible that the people building applications — even developers — will not know about all uses of thread_rng requiring secure randomness.
This brings me to ask, is having only a single user-facing function ideal? What if instead:
strong_rngreplacesthread_rngas a source of cryptographically secure randomnessweak_rngis added as a fast source of randomness; depending on feature flags this could just wrapstrong_rngor could be independent
An advantage of the above is that feature-flags could allow replacing the current implementation (HC-128; 4176 bytes) with two smaller back ends (e.g. ChaCha + PCG; 136 + 16 bytes), while only compromising the speed of the secure generator.
Another advantage is that we could add forward-secrecy to strong_rng with less concern for performance implications.
But first, why bother when generators like Randen and RDRAND claim to satisfy all requirements anyway? This is a good question to which I only have vague answers: Randen is still new and unproven and may have portability issues; RDRAND is not fully trusted; and may not be the fastest option.
Second, what about users like HashMap where weaknesses are often not exploitable (depending on application design and usage) and in the worst case only allow DOS attacks (slow algorithms)? Another good question. One possible answer is that these use-cases should use weak_rng but by default this would be secure anyway; we provide feature flags to change that but discourage usage on servers. It might seem tempting to add a third function, but, frankly, this kind of thing is probably the main use case for weak_rng anyway.
Another, very different, option is that we keep thread_rng looking like it is but remove CryptoRng support and recommend it not be used for crypto keys. Then we can add a feature flag changing its implementation to an insecure generator with less concern. This may be a good option, but goes against our recent changes (switching to HC-128 and implementing CryptoRng).
BTW, lets not bikeshed thread_rng vs ThreadRng::new or other syntax here.