The following table maps the implementation of the AES-CTR-DRBG to the requirements specified in NIST SP 800-90A Rev. 1. Each row corresponds to a specific requirement, detailing how it is implemented in the codebase.
| NIST SP 800-90A Requirement | Implementation Reference | Construction Step |
|---|---|---|
1. Instantiate: Acquire entropy and set initial state (Key and V) |
newDRBG() uses io.ReadFull(rand.Reader, ...) |
- Entropy input of KeySize + 16 bytes, split into key and counter (V) |
| - Personalization string (if provided) XORed into seed | ||
| - AES cipher constructed with key | ||
| - Initial counter (V) set from entropy | ||
| 2. Generate: For each output block, increment counter and encrypt | fillBlocks(), incV(), st.block.Encrypt(...) |
- For each 16-byte block: increment V (big-endian), AES-CTR encrypt, write to output buffer |
| 3. Generate with Additional Input (Optional) | ReadWithAdditionalInput([]byte) |
- Mixes provided additional input into state before generation, per NIST SP 800-90A |
| 4. Update State After Generation | Read(), fillBlocks(), state management |
- Updated counter (V) copied back to instance after each output |
| - Mutex on DRBG instance ensures thread safety | ||
| 5. Rekey/Reseed (Configurable/Optional): | asyncRekey(), Reseed([]byte), rekey logic |
- Supports rekey after configurable bytes generated (MaxBytesPerKey), interval (ReseedInterval), or request |
| - New entropy (and optional personalization) is acquired and state is swapped atomically | ||
| 6. Manual Reseed (Optional) | Reseed([]byte) |
- Allows caller to force a reseed with new entropy at any time |
| 7. Personalization Support (Optional): | newDRBG(), rekey use personalization |
- Personalization string applied at instantiation and rekey |
| 8. Prediction Resistance (Optional, §9.3): | WithPredictionResistance(true) |
- DRBG reseeds from fresh entropy before every output, as required by §9.3 |
| 9. Max Request Size (§10.2.1): | maxBytesPerRequest constant, ErrRequestTooLarge |
- Enforces 64 KB maximum per output request per NIST SP 800-90A §10.2.1 |
| 10. Reseed Interval Cap (§10.2.1.1): | maxReseedInterval constant in WithReseedRequests() |
- Clamps user-configured reseed interval to maximum of 2^48 requests |
| 11. Known Answer Tests (FIPS 140-2 §4.9.1): | RunSelfTests(), WithSelfTests(true) |
- Power-on self-tests using NIST CAVP test vectors to verify AES-CTR correctness |
| 12. Key Zeroization (FIPS 140-2 §4.7.6): | asyncRekey() with WithZeroization(true) |
- Secure erasure of old key material using crypto/subtle during key rotation for forward secrecy |
| 13. Edge Cases and Robustness: | Test suite; logic for zero/overflow | - Zero-length reads are no-ops, counter overflow (wrap) is supported, large/unaligned reads are allowed |
| 14. Error Handling: | Error returns/panics for entropy/cipher errors | - Instantiation returns error or panics on failure; rekey fails over to prior state if new entropy unavailable |
| 15. Concurrency: | Instance-level mutex; sharded pools | - Per-instance mutex ensures thread safety; sharding and pooling enable high concurrency |
| 16. Interface and Integration: | Implements io.Reader and ReadWithAdditionalInput |
- Compatible with Go APIs and libraries expecting io.Reader or custom input |
| 17. No External Dependencies: | Go standard library only | - Only Go standard cryptography primitives are used (no third-party dependencies) |
| 18. Continuous Health Test (NIST SP 800-90A §11.3.3): | continuousHealthTest(), WithContinuousHealthTest(true) |
- Compares each output block to previous; detects stuck DRBG output per NIST SP 800-90A §11.3.3 |