NIST SP 800-90A added three Deterministic Random Bit Generators (DRBGs) to secede the retired ANSI X9.17 and X9.31 generators. Crypto++ 5.7 added support for DRBGs at Commit 5c932fcc3b6333e4. The initial commit added the Hash_DRBG and CAVP test vectors. Later, Commit 2868452193e32156 added HMAC_DRBG and additional CAVP test vectors.
The NIST generators are provided header-only, so you can fetch the include file and use it in any version of the Crypto++ library. Just drop it in place and use it as if it was part of the release ZIP.
Using a NIST generator is a little trickier than using a typical RandomNumberGenerator from the library. They are trickier because they have randomness requirements during instantiation and reseed, and the source of the randomness matters. In addition, they accept at least three other types of randomness distinct from the entropy and randomness required during instantiation. This page will explain how to use them.
The Crypto++ NIST DRBGs provide Backtracking Resistance (BR). BR is a design feature, and all NIST DRBGs have it. The library's implementation does not provide Predictive Resistance (PR) as specified in SP 800-90A, Section 8.8, Prediction Resistance and Backtracking Resistance.
Though the generators are NIST approved and they complete the CAVP test vectors, the classes are not FIPS validated since the library and classes have not undergone CMVP testing.
The NIST deterministic generators are found in drbg.h. The base class is called NIST_DRBG, and it provides the interface for both Hash_DRBG and HMAC_DRBG. Both Hash_DRBG and HMAC_DRBG are templates, and they require a hash, a security strength in bytes, and a seed length in bytes.
Hash_DRBG(const byte* entropy, size_t entropyLength=STRENGTH, const byte* nonce=NULL, size_t nonceLength=0, const byte* personalization=NULL, size_t personalizationLength=0)
HMAC_DRBG(const byte* entropy, size_t entropyLength=STRENGTH, const byte* nonce=NULL, size_t nonceLength=0, const byte* personalization=NULL, size_t personalizationLength=0)
entropyLength is the size of the entropy buffer. The constant STRENGTH is the minimum entropy required to instantiate the generator. The parameter's value will change depending on the generator and the security strength.
nonce is additional entropy used to instantiate the generator. The nonce buffer is optional. The parameter is "weaker" than entropy, but "stronger" than the personalization string. Also see Randomness Source below.
nonceLength is the size of the nonce buffer.
personalization is additional entropy used to instantiate the generator. The personalization string is optional. The parameter is "weaker" than both entropy and nonce. Also see Randomness Source below.
personalizationLength is the size of the personalization buffer.
The following discusses requirements of entropy, nonce, persoanlization and additional input.
SP 800-90A, Section 8.6.5 Randomness Source states the following. Entropy is always required for instantiation and reseed.
A DRBG mechanism requires an approved randomness source during instantiation and reseeding, including whenever prediction resistance is requested (see Section 8.8). This input is requested using the Get_entropy_input function introduced in Section 9 and is specified in more detail in SP 800-90C.
An approved randomness source is an entropy source that conforms to SP 800-90B, or an RBG that conforms to SP 800-90C − either a DRBG or an NRBG.
SP 800-90A, Section 8.6.7, Nonce states the following when a nonce is required:
- A random value that is generated anew for each nonce, using an approved random bit generator.
- A timestamp of sufficient resolution (detail) so that it is different each time it is used.
- A monotonically increasing sequence number, or
- A combination of a timestamp and a monotonically increasing sequence number, such that the sequence number is reset when and only when the timestamp changes
SP 800-90A, Section 8.7.1, Personalization String states the following:
A personalization string is an optional (but recommended) input to the instantiate function and is used to derive the seed (see Section 8.6.1). The personalization string may be obtained from inside or outside a cryptographic module, and may be an empty string.
The intent of a personalization string is to introduce additional input into the instantiation of a DRBG. This personalization string might contain values unknown to an attacker, or values that tend to differentiate this DRBG instantiation from all others. Ideally, a personalization string will be set to some bitstring that is as unique as possible. Good sources for the personalization string contents include:
- Application identifiers
- Device serial numbers
- User identification
- Per-module or per-device values
- Network addresses
- Special key values for this specific DRBG instantiation
- Protocol version identifiers
- Random numbers and Nonces
- Outputs from other approved or non-approved random bit generators
SP 800-90A, Section 8.7.2 Additional Input states the following:
Additional input may optionally be provided to the reseed and generate functions during requests. The additional input may be obtained from inside or outside a cryptographic module, and may include secret or public information.
The NIST generators are tested in validat1.cpp in functions ValidateHash_DRBG() and ValidateHmac_DRBG(). The test vectors were taken from NIST's CAVP Testing: Random Number Generators.
You can execute the Hash_DRBG test vectors using cryptest.exe v 77 (HMAC_DRBG is 78). The tests exercise various instantiations of the generator using different combinations of entropy (E), nonce (N), additional entropy (A), and personalization strings (P).
$ ./cryptest.exe v 77 Using seed: 1483211134 Testing NIST DRBG generators... passed Hash_DRBG SHA1/128/440 (COUNT=0, E=16, N=8) passed Hash_DRBG SHA1/128/440 (COUNT=1, E=16, N=8) passed Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16) passed Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16) passed Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=0, P=16) passed Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=0, P=16) passed Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16, P=16) passed Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16, P=16) passed Hash_DRBG SHA256/128/440 (C0UNT=0, E=32, N=16, A=32, P=32) passed Hash_DRBG SHA256/128/440 (C0UNT=1, E=32, N=16, A=32, P=32) passed Hash_DRBG SHA512/256/888 (C0UNT=0, E=32, N=16, A=32, P=32) passed Hash_DRBG SHA512/256/888 (C0UNT=1, E=32, N=16, A=32, P=32) Test ended at Sat Dec 31 14:05:34 2016
The following shows how you might use the NIST generators. The generators are unique becuase they effectively need an external generator to provide the initial entropy used during instantiation and entropy used during reseed.
An example of instantiating a SHA256 generator is shown below. The example provides more entropy than required for SHA256. The NonblockingRng meets the requirements of NIST SP 800-90B. RDRAND and RDSEED generators would work as well.
NIST instantiation requirements demand the generator is constructed with at least MINIMUM_ENTROPY entropy, which is 16 in the case of SHA256. However, a 32-byte entropy string is provided below. A nonce is not required for Hash_DRBG, but a 16 byte nonce is provided (other NIST DRBGs require a nonce).
SecByteBlock entropy(48), result(128); NonblockingRng prng; RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size())); Hash_DRBG<SHA256, 128/8, 440/8> drbg(entropy, 32, entropy+32, 16); drbg.GenerateBlock(result, result.size()); ...
The generator has the same entropy requirements during reseed operations (there are no nonce requirements). If you reseed after each generate operation, than you satisfy the requirements for Predictive Resistance (PR).
prng.GenerateBlock(entropy, entropy.size()); drbg.IncorporateEntropy(entropy, entropy.size()); drbg.GenerateBlock(result, result.size()); ...