Skip to content

Is CryptoRng useful? #543

@dhardy

Description

@dhardy

Perhaps this can stay open for a while as a discussion item. I'd especially like feedback from lib users who have looked at this trait.

This trait has requirements on the PRNG algorithm, but not the seeding method (as comes up in #537):

/// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`]
/// implementation is supposed to be cryptographically secure.
/// 
/// *Cryptographically secure generators*, also known as *CSPRNGs*, should
/// satisfy an additional properties over other generators: given the first
/// *k* bits of an algorithm's output
/// sequence, it should not be possible using polynomial-time algorithms to
/// predict the next bit with probability significantly greater than 50%.
/// 
/// Some generators may satisfy an additional property, however this is not
/// required by this trait: if the CSPRNG's state is revealed, it should not be
/// computationally-feasible to reconstruct output prior to this. Some other
/// generators allow backwards-computation and are consided *reversible*.
/// 
/// Note that this trait is provided for guidance only and cannot guarantee
/// suitability for cryptographic applications. In general it should only be
/// implemented for well-reviewed code implementing well-regarded algorithms.
/// 
/// Note also that use of a `CryptoRng` does not protect against other
/// weaknesses such as seeding from a weak entropy source or leaking state.
/// 
/// [`RngCore`]: trait.RngCore.html
/// [`BlockRngCore`]: ../rand_core/block/trait.BlockRngCore.html
pub trait CryptoRng {}

The trait can guarantee absolutely nothing about the quality of the seed used on the PRNG. For example, it would be quite easy to write:

let key = [0u8; 32];
// TODO: randomise the key
let rng = ChaChaRng::from_seed(key);

and forget to actually add any entropy to the system.

Or, in some ways worse (because it is harder to spot), the key could be written using a non-crypto RNG (stretching an insecure key).

There is no easy way to guard against insecure seeding (and even if there were, there are other ways to go wrong in cryptography). Even if we added a function like this it wouldn't really help:

pub trait CryptoRng {
    /// Implementations must estimate the number of bits of entropy in their seed
    fn estimate_entropy(&self) -> u32;
}

It would be simple enough to detect seeds with too many 0s or 1s, but still extra complexity to implement. Detecting that the seed was set by a weak PRNG however would be much much harder (computationally very expensive and very complex) — this is not viable.

Summary: security is a property of the complete implementation, not just the type.

So my conclusion: CryptoRng appears to be making a promise it cannot guarantee when implemented on PRNG algorithms.

Options:

  1. Keep the status quo; rely on documentation
  2. Remove implementation of CryptoRng from PRNG algorithms and keep only on OsRng, JitterRng, EntropyRng and ThreadRng (which all manage their own seeding or directly get entropy from external sources)
  3. Remove the CryptoRng trait altogether

Metadata

Metadata

Assignees

No one assigned

    Labels

    E-questionParticipation: opinions wantedX-securitySecurity discussion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions