CPRNG(9)

πŸ“¦ version 11.0, in nixpkgs unstable

πŸ’… CPRNG(9) β€” the kernel dev manual, bestie edition πŸŽ€

ok so this is CPRNG(9), straight out of the Kernel Developer's Manual, and it's literally all about the kernel's random number situation. stay with me, it's actually so good.


✨ NAME ✨

cprng, cprng_strong_create, cprng_strong_destroy, cprng_strong, cprng_strong32, cprng_strong64, cprng_fast, cprng_fast32, cprng_fast64 β€” cryptographic pseudorandom number generators 🎲

like, the whole squad. all of them. and they're cryptographic, which is the good kind, no cap.


🌸 SYNOPSIS 🌸

#include <sys/cprng.h>

cprng_strong_t *
cprng_strong_create(const char *name, int ipl, int flags);

void
cprng_strong_destroy(cprng_strong_t *cprng);

size_t
cprng_strong(cprng_strong_t *cprng, void *buf, size_t len, int flags);

uint32_t
cprng_strong32(void);

uint64_t
cprng_strong64(void);

size_t
cprng_fast(void *buf, size_t len);

uint32_t
cprng_fast32(void);

uint64_t
cprng_fast64(void);

#define CPRNG_MAX_LEN   524288

and yes bestie, that #define CPRNG_MAX_LEN 524288 is part of the package. remember that number, it comes back later πŸ‘€


πŸ’– DESCRIPTION πŸ’–

okay so the cprng family of functions provides cryptographic pseudorandom number generators that are automatically seeded from the kernel entropy pool. automatic. you don't gotta do anything. it just knows. ✨

the vibe check: all applications in the kernel that require random data or random choices should use the cprng_strong family of functions β€” unless performance constraints demand otherwise. that's the rule. that's the assignment.

the cprng_fast family of functions may be used in applications that can tolerate exposure of past random data β€” think initialization vectors, or transaction ids that are sent over the internet anyway πŸ™ˆ β€” but only if the applications require higher throughput or lower per-request latency than the cprng_strong family of functions provide. and if you're in doubt? cprng_strong. always. pick cprng_strong. it's giving responsible main character energy πŸ‘‘

a single instance of the fast generator serves the entire kernel. one. just the one. meanwhile, a well-known instance of the strong generator, kern_cprng, may be used by any in-kernel caller β€” but you can also create separately seeded instances of the strong generator by calling cprng_strong_create(). build your own. iconic.

the cprng functions may be used in soft interrupt context, except for cprng_strong_create() and cprng_strong_destroy() which are allowed only at IPL_NONE in thread context β€” see spl(9). those two are the picky ones, they need their space 🫢

and the glow-up lore: the cprng functions replace the legacy arc4random(9) and rnd_extract_data(9) functions. out with the old, in with the new. periodt. πŸ’…


πŸ¦‹ FUNCTIONS πŸ¦‹

🌈 cprng_strong_create(name, ipl, flags)

create an instance of the cprng_strong generator. this generator currently implements the NIST SP 800-90A Hash_DRBG with SHA-256 as the hash function. fancy. certified. credentialed. πŸŽ“

the name argument is used to "personalize" the Hash_DRBG according to the standard, so that its initial state will depend both on seed material from the entropy pool and also on the personalization string (name). it's literally the generator's name tag at the party.

the ipl argument specifies the interrupt priority level for the mutex which will serialize access to the new instance of the generator (see spl(9)), and must be no higher than IPL_SOFTSERIAL. that's a hard ceiling, bestie, don't push it 🚫

the flags argument must be zero. zero. that's it. that's the number.

creation will succeed even if full entropy for the generator is not available. in this case, the first request to read from the generator may cause reseeding. so like, it works, it just might need a lil top-up on first use πŸ”‹

cprng_strong_create() may sleep to allocate memory. plan accordingly 😴

πŸ’œ cprng_strong_destroy(cprng)

destroy cprng. that's it. bye babe πŸ‘‹

cprng_strong_destroy() may sleep.

πŸ“ cprng_strong(cprng, buf, len, flags)

fill memory location buf with up to len bytes from the generator cprng, and return the number of bytes. len must be at most CPRNG_MAX_LEN β€” remember that 524288 from the synopsis? yeah. that one. β€” and flags must be zero. zero again. always zero πŸ”₯

⭐ cprng_strong32()

generate 32 bits using the kern_cprng strong generator. ✨

cprng_strong32() does not sleep.

⭐ cprng_strong64()

generate 64 bits using the kern_cprng strong generator. double the bits, double the slay.

cprng_strong64() does not sleep.

🧚 cprng_fast(buf, len)

fill memory location buf with len bytes from the fast generator. zoom zoom. πŸ’¨

cprng_fast() does not sleep.

🧚 cprng_fast32()

generate 32 bits using the fast generator.

cprng_fast32() does not sleep.

🧚 cprng_fast64()

generate 64 bits using the fast generator.

cprng_fast64() does not sleep.

πŸ” SECURITY MODEL πŸ”

ok this is the part where we get serious for a sec, because it's literally the whole point. the cprng family of functions provides the following security properties:

  • an attacker who has seen some outputs of any of the cprng functions cannot predict past or future unseen outputs. πŸ’€
  • an attacker who has compromised kernel memory cannot predict past outputs of the cprng_strong functions. however, such an attacker may be able to predict past outputs of the cprng_fast functions. 😭

the second property is sometimes called "backtracking resistance", "forward secrecy", or "key erasure" in the cryptography literature β€” iykyk. and to be crystal clear:

  • the cprng_strong functions provide backtracking resistance. πŸ‘‘
  • the cprng_fast functions do not. πŸ™ˆ

that's the whole trade-off. that's why the strong one is the default recommendation. no notes.


🫢 CODE REFERENCES 🫢

the cprng_strong functions are implemented in sys/kern/subr_cprng.c, and use the NIST SP 800-90A Hash_DRBG implementation in sys/crypto/nist_hash_drbg.

the cprng_fast functions are implemented in sys/crypto/cprng_fast/cprng_fast.c, and use the ChaCha8 stream cipher. πŸŒ€

like, go read the source, it's right there, it's giving open book exam.


πŸ‘€ SEE ALSO πŸ‘€

and the reading list, because citations are hot:

  • Elaine Barker and John Kelsey, Recommendation for Random Number Generation Using Deterministic Random Bit Generators (Revised), National Institute of Standards and Technology, 2011, NIST Special Publication 800-90A, Rev 1.
  • Daniel J. Bernstein, ChaCha, a variant of Salsa20, http://cr.yp.to/papers.html#chacha, 2008-01-28, Document ID: 4027b5256e17b9796842e6d0f68b0b5e.

πŸ•°οΈ HISTORY πŸ•°οΈ

The cprng family of functions first appeared in NetBSD 6.0. a classic. a legend. the origin story we deserved πŸ’–


and that's the page, bestie πŸŽ€ this one's from the Debian build, dated August 16, 2020 β€” go forth and generate cryptographically secure randomness responsibly, and remember: if in doubt, cprng_strong. always. 🌈✨

πŸ“¦ where this page comes from