Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals
Examine the internal state and output generation of each approved NIST DRBG mechanism.
Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals is a free Cryptology Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Cryptology Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
DRBG Internal State Components
Each of the three NIST DRBG mechanisms maintains different internal state components, reflecting their underlying algorithmic approach. Hash_DRBG stores V (a hash-length seed) and C (a constant derived from V used during output generation). HMAC_DRBG stores Key K (a hash-length secret key) and Value V (a hash-length chaining value). CTR_DRBG stores Key K (an AES key) and V (a block-length counter). All three maintain a reseed_counter tracking generate calls since last seeding. The state size determines the memory footprint: Hash/HMAC_DRBG with SHA-256 use 64 bytes of state; CTR_DRBG with AES-256 uses 48 bytes (32-byte key + 16-byte counter).
Hash_DRBG: Hash_df Derivation Function
Hash_DRBG uses Hash_df (hash derivation function) to derive state from entropy material. Hash_df(input_string, no_of_bits_to_return) iterates: for counter = 1, 2, ..., compute H(counter || no_of_bits || input_string) and concatenate outputs until enough bits are produced. This stretches short entropy inputs into state-sized seeds. During Generate, the output function computes W = H(0x03 || V) where the 0x03 prefix distinguishes this from other hash uses. The output loop: data = H(0x01 || V); V = V + 1; repeat for more output. After generating, V is updated: V = V + H(0x03 || V) + C + reseed_counter. The domain separation via prefix bytes (0x01, 0x03) prevents output from the generate phase being confused with the state update phase.
HMAC_DRBG: Update Function
HMAC_DRBG's Update function is the core of all state transitions. Update(provided_data, K, V): K = HMAC(K, V || 0x00 || provided_data); V = HMAC(K, V). If provided_data is not empty: K = HMAC(K, V || 0x01 || provided_data); V = HMAC(K, V). This two-step update ensures that new key and value both depend on the previous state and any new entropy. Generate: loop V = HMAC(K, V) and append to output until enough bits are produced; then call Update with additional_input to advance state. The security of HMAC_DRBG reduces to the assumption that HMAC is a secure PRF: an adversary who cannot distinguish HMAC output from random cannot distinguish DRBG output from random.
CTR_DRBG: Block_Cipher_df
CTR_DRBG uses Block_Cipher_df (derivation function) to process seed material into key/counter format. Block_Cipher_df(input_string, no_of_bits) uses a BCC (Block Cipher Chaining) construction: iterates AES-CBC over input chunks to produce an output of the required length. The derivation function is necessary to handle variable-length entropy inputs and to provide domain separation. CTR_DRBG without a derivation function (allowed for FIPS testing with precisely formatted inputs) is faster but more sensitive to input format requirements. The Generate loop: temp = E(K, V); V = V + 1; append temp to output. Update: K || V = Block_Cipher_df(V || additional_input, seedlen); apply XOR with current key.
Comparing DRBG Performance
Performance varies significantly across DRBG types. On a modern x86_64 CPU with AES-NI: CTR_DRBG (AES-256) achieves approximately 5-10 GB/s of pseudorandom output — the AES-NI instruction makes AES computation near-free. HMAC_DRBG (SHA-256) achieves approximately 200-400 MB/s — SHA-256 is fast but not hardware-accelerated to the same degree. Hash_DRBG (SHA-256) achieves approximately 100-300 MB/s. For bulk key generation or stream cipher replacement, CTR_DRBG is dramatically faster. For low-throughput uses (session key generation, nonce derivation), the performance difference is insignificant. OpenSSL 3.0 uses CTR_DRBG (AES-256) as the default for this reason.
Instantiation and Personalization Strings
At instantiation, all three DRBGs accept an optional personalization_string that is mixed with the entropy input to make the DRBG instance unique. This prevents two concurrently instantiated DRBGs with the same entropy from producing the same output — they diverge based on the personalization string. Recommended personalization strings: application identifier + process ID + thread ID + timestamp + a hardware identifier. Even if two VMs receive the same entropy (a cloud VM snapshot problem), different personalization strings ensure different DRBG streams. NIST SP 800-90C recommends always using a personalization string. The nonce parameter serves a similar purpose: a unique short value ensuring that no two instantiations begin in the same state.
Additional Input in Generate Calls
All three DRBGs support an additional_input parameter in Generate calls. This allows the caller to inject additional context or entropy into a single generate call without a full reseed. Uses: (1) injecting per-request entropy from a secondary entropy source; (2) providing application-level context (request ID, timestamp) to bind generated values to their usage; (3) providing optional prediction resistance by injecting fresh entropy from the OS. Additional_input is mixed into the DRBG state before output generation. If the additional_input provides real entropy, it improves security without requiring a formal reseed (which involves the entropy source interface and associated overhead).
State Zeroization and Key Destruction
After a DRBG is uninstantiated (or when switching to a new instance), the internal state must be securely zeroized. State V, C (Hash_DRBG), K, V (HMAC/CTR_DRBG), and all intermediate working variables must be overwritten with zeros. This is called explicit zeroization and is mandatory in FIPS 140-3 modules. In C code, use explicit_bzero() or SecureZeroMemory() — a compiler-optimized memset may be removed as a dead-store optimization, leaving key material in memory. Rust's zeroize crate and similar language-specific solutions handle this portably. Secure key destruction is important in contexts where memory dumps, cold boot attacks, or process inspection tools might expose residual state.
DRBG Testing: CAVP Vectors
NIST provides Cryptographic Algorithm Validation Program (CAVP) test vectors for all SP 800-90A DRBGs. Test types: (1) Known Answer Tests (KATs) — given a fixed entropy input, nonce, and personalization string, verify the generated output matches precomputed values. (2) Reseed tests — verify the DRBG state after a reseed operation. (3) PR (Prediction Resistance) tests — verify that requesting prediction_resistance=true produces correct output after injecting fresh entropy. CAVP validation is required for FIPS 140-3 submission. Open-source libraries (OpenSSL, mbedTLS) include CAVP test vectors in their regression test suites to catch regressions in DRBG implementations.
Side-Channel Risks in DRBG Implementations
DRBG implementations face subtle side-channel risks beyond the algorithmic security model. Cache-timing attacks on AES (in CTR_DRBG without AES-NI) can leak round key material; AES-NI eliminates this by computing in registers with no table lookups. HMAC_DRBG uses HMAC internally, which is constant-time if the underlying SHA-256 is constant-time — SHA-256 is generally considered constant-time since it has no data-dependent branches. Physical side channels (power analysis, EM radiation) against DRBG-producing hardware are a concern for smart cards and IoT devices, addressed by masking implementations. The state backup attack: if an adversary can read DRBG state via a memory disclosure vulnerability (Heartbleed-style), all future output is compromised until the next reseed with fresh entropy.
DRBG State Recovery after Compromise
If a DRBG state is compromised (e.g., via a memory disclosure vulnerability), recovery requires: (1) Detecting the compromise — DRBG state leaks are not self-evident; external monitoring or integrity checks are needed. (2) Reseeding with fresh entropy from a trusted source not involved in the compromise. (3) Rekeying all cryptographic material derived from the compromised DRBG (session keys, signing keys generated since last healthy reseed). (4) For software implementations, restarting the process provides a clean DRBG instantiation. SP 800-90C recommends chained entropy sources — if one source is compromised, the combination still provides security if the other source provides real entropy.
DRBG State Quiz
Which DRBG mechanism is fastest for bulk pseudorandom output generation on modern CPUs?
DRBG Internals Recap
Hash_DRBG uses iterative hashing with Hash_df for derivation, producing output via H(0x01 || V) loops. HMAC_DRBG uses HMAC as a PRF with a two-step Update function (key then value) providing clean security reduction. CTR_DRBG uses AES in counter mode with Block_Cipher_df, achieving 5-10 GB/s on AES-NI hardware. All accept personalization_string at instantiation for instance uniqueness and additional_input per generate for context binding. CAVP test vectors validate implementations. State must be securely zeroized after use. State compromise requires reseed with fresh entropy and rekeying of derived material.
Frequently asked questions
Is the “Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals” lesson free?
Yes — the full text of “Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals” is free to read here on the web, and the Cryptology Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Cryptology Academy course, upgrade to CoddyKit PRO.
What will I learn in “Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals”?
Examine the internal state and output generation of each approved NIST DRBG mechanism. You practise Cryptology Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Cryptology Academy?
No prior experience is required. Cryptology Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Cryptology Academy lesson?
Yes. Every Cryptology Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- NIST SP 800-90A: DRBG Standards
- Hash-DRBG, HMAC-DRBG, and CTR-DRBG Internals
- The Dual EC DRBG Backdoor Incident
- Testing and Validating RNG Implementations