-class Hash_DRBG : public NIST_DRBG
+class Hash_DRBG : public NIST_DRBG, public NotCopyable
{
public:
- CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH)
- CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH)
- CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH)
- CRYPTOPP_CONSTANT(MINIMUM_NONCE=0)
- CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0)
- CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0)
- CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX)
- CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX)
- CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX)
- CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX)
- CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536)
- CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX)
+ CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH)
+ CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH)
+ CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH)
+ CRYPTOPP_CONSTANT(MINIMUM_NONCE=0)
+ CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0)
+ CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0)
+ CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536)
+ CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX)
- //! \brief Construct a Hash DRBG
- //! \param entropy the entropy to instantiate the generator
- //! \param entropyLength the size of the entropy buffer
- //! \param nonce additional input to instantiate the generator
- //! \param nonceLength the size of the nonce buffer
- //! \param personalization additional input to instantiate the generator
- //! \param personalizationLength the size of the personalization buffer
- //! \throws NIST_DRBG::Err if the generator is instantiated with insufficient entropy
- //! \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy.
- //! The byte array for entropy must meet NIST
- //! SP 800-90B or SP 800-90C requirements.
- //! \details The nonce and personalization are optional byte arrays. If nonce is supplied,
- //! then it should be at least MINIMUM_NONCE bytes of entropy.
- //! \details 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 or SP 800-90C.
- //! RDRAND() and RDSEED() generators would work as well.
- //!
- //! SecByteBlock entropy(48), result(128);
- //! NonblockingRng prng;
- //! RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
- //!
- //! Hash_DRBG drbg(entropy, 32, entropy+32, 16);
- //! drbg.GenerateBlock(result, result.size());
- //!
- 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)
- : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH)
- {
- DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
- }
+ //! \brief Construct a Hash DRBG
+ //! \param entropy the entropy to instantiate the generator
+ //! \param entropyLength the size of the entropy buffer
+ //! \param nonce additional input to instantiate the generator
+ //! \param nonceLength the size of the nonce buffer
+ //! \param personalization additional input to instantiate the generator
+ //! \param personalizationLength the size of the personalization buffer
+ //! \throws NIST_DRBG::Err if the generator is instantiated with insufficient entropy
+ //! \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy.
+ //! The byte array for entropy must meet NIST
+ //! SP 800-90B or SP 800-90C requirements.
+ //! \details The nonce and personalization are optional byte arrays. If nonce is supplied,
+ //! then it should be at least MINIMUM_NONCE bytes of entropy.
+ //! \details 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 or SP 800-90C.
+ //! RDRAND() and RDSEED() generators would work as well.
+ //!
+ //! SecByteBlock entropy(48), result(128);
+ //! NonblockingRng prng;
+ //! RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+ //!
+ //! Hash_DRBG drbg(entropy, 32, entropy+32, 16);
+ //! drbg.GenerateBlock(result, result.size());
+ //!
+ 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)
+ : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH)
+ {
+ DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+ }
- unsigned int GetSecurityStrength() const {return SECURITY_STRENGTH;}
- unsigned int GetSeedLength() const {return SEED_LENGTH;}
- unsigned int GetMinEntropy() const {return MINIMUM_ENTROPY;}
- unsigned int GetMaxEntropy() const {return MAXIMUM_ENTROPY;}
- unsigned int GetMinNonce() const {return MINIMUM_NONCE;}
- unsigned int GetMaxNonce() const {return MAXIMUM_NONCE;}
- unsigned int GetMaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;}
- unsigned int GetMaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;}
+ unsigned int GetSecurityStrength() const {return SECURITY_STRENGTH;}
+ unsigned int GetSeedLength() const {return SEED_LENGTH;}
+ unsigned int GetMinEntropy() const {return MINIMUM_ENTROPY;}
+ unsigned int GetMaxEntropy() const {return MAXIMUM_ENTROPY;}
+ unsigned int GetMinNonce() const {return MINIMUM_NONCE;}
+ unsigned int GetMaxNonce() const {return MAXIMUM_NONCE;}
+ unsigned int GetMaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;}
+ unsigned int GetMaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;}
- void IncorporateEntropy(const byte *input, size_t length)
- {return DRBG_Reseed(input, length, NULL, 0);}
+ void IncorporateEntropy(const byte *input, size_t length)
+ {return DRBG_Reseed(input, length, NULL, 0);}
- void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
- {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);}
+ void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+ {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);}
- void GenerateBlock(byte *output, size_t size)
- {return Hash_Generate(NULL, 0, output, size);}
+ void GenerateBlock(byte *output, size_t size)
+ {return Hash_Generate(NULL, 0, output, size);}
- void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)
- {return Hash_Generate(additional, additionaLength, output, size);}
+ void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)
+ {return Hash_Generate(additional, additionaLength, output, size);}
protected:
- // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.58)
- void Hash_df(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2,
- const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen)
- {
- HASH hash;
- byte counter = 1;
- word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8));
+ // 10.1.1.2 Instantiation of Hash_DRBG (p.39)
+ void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+ const byte* personalization, size_t personalizationLength);
- size_t count;
- for (count=0; outlen; outlen -= count, output += count, counter++)
- {
- hash.Update(&counter, 1);
- hash.Update(reinterpret_cast(&bits), 4);
+ // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40)
+ void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength);
- if (input1 && inlen1)
- hash.Update(input1, inlen1);
- if (input2 && inlen2)
- hash.Update(input2, inlen2);
- if (input3 && inlen3)
- hash.Update(input3, inlen3);
- if (input4 && inlen4)
- hash.Update(input4, inlen4);
+ // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41)
+ void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size);
- count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE);
- hash.TruncatedFinal(output, count);
- }
- }
-
- // 10.1.1.2 Instantiation of Hash_DRBG (p.48)
- void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
- const byte* personalization, size_t personalizationLength)
- {
- // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
- // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
- // personalization string during instantiation, or in the additional input during reseeding and generation,
- // but this is not required and does not increase the "official" security strength of the DRBG
- // instantiation that is recorded in the internal state.
- CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
- if (entropyLength < MINIMUM_ENTROPY)
- throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate");
-
- // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
- // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
- CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
- CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE);
- CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION);
-
- const byte zero = 0;
- SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
- Hash_df(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULL, 0, t1, t1.size());
- Hash_df(&zero, 1, t1, t1.size(), NULL, 0, NULL, 0, t2, t2.size());
-
- m_v.swap(t1); m_c.swap(t2);
- m_reseed = 1;
- }
-
- // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.49)
- void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
- {
- // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
- // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
- // personalization string during instantiation, or in the additional input during reseeding and generation,
- // but this is not required and does not increase the "official" security strength of the DRBG
- // instantiation that is recorded in the internal state..
- CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
- if (entropyLength < MINIMUM_ENTROPY)
- throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed");
-
- // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
- // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
- CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
- CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
-
- const byte zero = 0, one = 1;
- SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
- Hash_df(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size());
- Hash_df(&zero, 1, t1, t1.size(), NULL, 0, NULL, 0, t2, t2.size());
-
- m_v.swap(t1); m_c.swap(t2);
- m_reseed = 1;
- }
-
- // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.50)
- void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size)
- {
- // Step 1
- if (static_cast(m_reseed) >= static_cast(GetMaxRequestBeforeReseed()))
- throw NIST_DRBG::Err("Hash_DRBG", "Reseed required");
-
- if (size > GetMaxBytesPerRequest())
- throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit");
-
- // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
- // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
- CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
-
- // Step 2
- if (additional && additionaLength)
- {
- HASH hash;
- const byte two = 2;
- SecByteBlock w(HASH::DIGESTSIZE);
-
- hash.Update(&two, 1);
- hash.Update(m_v, m_v.size());
- hash.Update(additional, additionaLength);
- hash.Final(w);
-
- CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
- int carry=0, i=SEEDLENGTH-1, j=HASH::DIGESTSIZE-1;
- while(i>=0 && j>=0)
- {
- carry = m_v[i] + w[j] + carry;
- m_v[i] = static_cast(carry);
- carry >>= 8; i--; j--;
- }
- while (carry && i>=0)
- {
- carry = m_v[i] + carry;
- m_v[i] = static_cast(carry);
- carry >>= 8; i--;
- }
- }
-
- // Step 3
- {
- HASH hash;
- SecByteBlock data(m_v);
-
- size_t count;
- for (count = 0; size; size -= count, output += count)
- {
- hash.Update(data, data.size());
- count = STDMIN(size, (size_t)HASH::DIGESTSIZE);
- hash.TruncatedFinal(output, count);
-
- IncrementCounterByOne(data, static_cast(data.size()));
- }
- }
-
- // Steps 4-7
- {
- HASH hash;
- const byte three = 3;
- SecByteBlock h(HASH::DIGESTSIZE);
-
- hash.Update(&three, 1);
- hash.Update(m_v, m_v.size());
- hash.Final(h);
-
- CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
- CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed));
- int carry=0, i=SEEDLENGTH-1, j=HASH::DIGESTSIZE-1, k=sizeof(m_reseed)-1;
- while(i>=0 && j>=0 && k>=0)
- {
- carry = m_v[i] + m_c[i] + h[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry;
- m_v[i] = static_cast(carry);
- carry >>= 8; i--; j--; k--;
- }
- while(i>=0 && j>=0)
- {
- carry = m_v[i] + m_c[i] + h[j] + carry;
- m_v[i] = static_cast(carry);
- carry >>= 8; i--; j--;
- }
- while (i>=0)
- {
- carry = m_v[i] + m_c[i] + carry;
- m_v[i] = static_cast(carry);
- carry >>= 8; i--;
- }
- }
-
- m_reseed++;
- }
+ // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49)
+ void Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2,
+ const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen);
private:
- SecByteBlock m_c, m_v;
- word64 m_reseed;
+ SecByteBlock m_c, m_v;
+ word64 m_reseed;
};
+// typedef Hash_DRBG Hash_SHA1_DRBG;
+// typedef Hash_DRBG Hash_SHA256_DRBG;
+// typedef Hash_DRBG Hash_SHA384_DRBG;
+// typedef Hash_DRBG Hash_SHA512_DRBG;
+
+// *************************************************************
+
+//! \class HMAC_DRBG
+//! \tparam HASH NIST approved hash derived from HashTransformation
+//! \tparam STRENGTH security strength, in bytes
+//! \tparam SEEDLENGTH seed length, in bytes
+//! \brief HMAC_DRBG from SP 800-90A Rev 1 (June 2015)
+//! \details The NIST Hash DRBG is instantiated with a number of parameters. Two of the parameters,
+//! Security Strength and Seed Length, depend on the hash and are specified as template parameters.
+//! The remaining parameters are included in the class. The parameters and their values are listed
+//! in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38).
+//! \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 248 requests
+//! before a reseed. However, HMAC_DRBG limits it to INT_MAX due to the limited data range of an int.
+//! \sa Recommendation
+//! for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015)
+//! \since Crypto++ 5.7
+template
+class HMAC_DRBG : public NIST_DRBG, public NotCopyable
+{
+public:
+ CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH)
+ CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH)
+ CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH)
+ CRYPTOPP_CONSTANT(MINIMUM_NONCE=0)
+ CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0)
+ CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0)
+ CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX)
+ CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536)
+ CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX)
+
+ //! \brief Construct a Hash DRBG
+ //! \param entropy the entropy to instantiate the generator
+ //! \param entropyLength the size of the entropy buffer
+ //! \param nonce additional input to instantiate the generator
+ //! \param nonceLength the size of the nonce buffer
+ //! \param personalization additional input to instantiate the generator
+ //! \param personalizationLength the size of the personalization buffer
+ //! \throws NIST_DRBG::Err if the generator is instantiated with insufficient entropy
+ //! \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy.
+ //! The byte array for entropy must meet NIST
+ //! SP 800-90B or SP 800-90C requirements.
+ //! \details The nonce and personalization are optional byte arrays. If nonce is supplied,
+ //! then it should be at least MINIMUM_NONCE bytes of entropy.
+ //! \details 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 or SP 800-90C.
+ //! RDRAND() and RDSEED() generators would work as well.
+ //!
+ //! SecByteBlock entropy(48), result(128);
+ //! NonblockingRng prng;
+ //! RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+ //!
+ //! HMAC_DRBG drbg(entropy, 32, entropy+32, 16);
+ //! drbg.GenerateBlock(result, result.size());
+ //!
+ 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)
+ : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE)
+ {
+ DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+ }
+
+ unsigned int GetSecurityStrength() const {return SECURITY_STRENGTH;}
+ unsigned int GetSeedLength() const {return SEED_LENGTH;}
+ unsigned int GetMinEntropy() const {return MINIMUM_ENTROPY;}
+ unsigned int GetMaxEntropy() const {return MAXIMUM_ENTROPY;}
+ unsigned int GetMinNonce() const {return MINIMUM_NONCE;}
+ unsigned int GetMaxNonce() const {return MAXIMUM_NONCE;}
+ unsigned int GetMaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;}
+ unsigned int GetMaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;}
+
+ void IncorporateEntropy(const byte *input, size_t length)
+ {return DRBG_Reseed(input, length, NULL, 0);}
+
+ void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+ {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);}
+
+ void GenerateBlock(byte *output, size_t size)
+ {return HMAC_Generate(NULL, 0, output, size);}
+
+ void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)
+ {return HMAC_Generate(additional, additionaLength, output, size);}
+
+protected:
+ // 10.1.2.3 Instantiation of HMAC_DRBG (p.45)
+ void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+ const byte* personalization, size_t personalizationLength);
+
+ // 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46)
+ void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength);
+
+ // 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46)
+ void HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size);
+
+ // 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44)
+ void HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3);
+
+private:
+ SecByteBlock m_k, m_v;
+ word64 m_reseed;
+};
+
+// typedef HMAC_DRBG HMAC_SHA1_DRBG;
+// typedef HMAC_DRBG HMAC_SHA256_DRBG;
+// typedef HMAC_DRBG HMAC_SHA384_DRBG;
+// typedef HMAC_DRBG HMAC_SHA512_DRBG;
+
+// *************************************************************
+
+// 10.1.1.2 Instantiation of Hash_DRBG (p.39)
+template
+void Hash_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+ const byte* personalization, size_t personalizationLength)
+{
+ // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+ // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+ // personalization string during instantiation, or in the additional input during reseeding and generation,
+ // but this is not required and does not increase the "official" security strength of the DRBG
+ // instantiation that is recorded in the internal state.
+ CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+ if (entropyLength < MINIMUM_ENTROPY)
+ throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+ CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE);
+ CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION);
+
+ const byte zero = 0;
+ SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
+ Hash_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULL, 0, t1, t1.size());
+ Hash_Update(&zero, 1, t1, t1.size(), NULL, 0, NULL, 0, t2, t2.size());
+
+ m_v.swap(t1); m_c.swap(t2);
+ m_reseed = 1;
+}
+
+// 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40)
+template
+void Hash_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+{
+ // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+ // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+ // personalization string during instantiation, or in the additional input during reseeding and generation,
+ // but this is not required and does not increase the "official" security strength of the DRBG
+ // instantiation that is recorded in the internal state..
+ CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+ if (entropyLength < MINIMUM_ENTROPY)
+ throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+ CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+ const byte zero = 0, one = 1;
+ SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH);
+ Hash_Update(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size());
+ Hash_Update(&zero, 1, t1, t1.size(), NULL, 0, NULL, 0, t2, t2.size());
+
+ m_v.swap(t1); m_c.swap(t2);
+ m_reseed = 1;
+}
+
+// 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41)
+template
+void Hash_DRBG::Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size)
+{
+ // Step 1
+ if (static_cast(m_reseed) >= static_cast(GetMaxRequestBeforeReseed()))
+ throw NIST_DRBG::Err("Hash_DRBG", "Reseed required");
+
+ if (size > GetMaxBytesPerRequest())
+ throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+ // Step 2
+ if (additional && additionaLength)
+ {
+ HASH hash;
+ const byte two = 2;
+ SecByteBlock w(HASH::DIGESTSIZE);
+
+ hash.Update(&two, 1);
+ hash.Update(m_v, m_v.size());
+ hash.Update(additional, additionaLength);
+ hash.Final(w);
+
+ CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
+ int carry=0, i=SEEDLENGTH-1, j=HASH::DIGESTSIZE-1;
+ while(i>=0 && j>=0)
+ {
+ carry = m_v[i] + w[j] + carry;
+ m_v[i] = static_cast(carry);
+ carry >>= 8; i--; j--;
+ }
+ while (carry && i>=0)
+ {
+ carry = m_v[i] + carry;
+ m_v[i] = static_cast(carry);
+ carry >>= 8; i--;
+ }
+ }
+
+ // Step 3
+ {
+ HASH hash;
+ SecByteBlock data(m_v);
+
+ while (size)
+ {
+ hash.Update(data, data.size());
+ size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE);
+ hash.TruncatedFinal(output, count);
+
+ IncrementCounterByOne(data, static_cast(data.size()));
+ output += count; size -= count;
+ }
+ }
+
+ // Steps 4-7
+ {
+ HASH hash;
+ const byte three = 3;
+ SecByteBlock h(HASH::DIGESTSIZE);
+
+ hash.Update(&three, 1);
+ hash.Update(m_v, m_v.size());
+ hash.Final(h);
+
+ CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE);
+ CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed));
+ int carry=0, i=SEEDLENGTH-1, j=HASH::DIGESTSIZE-1, k=sizeof(m_reseed)-1;
+ while(i>=0 && j>=0 && k>=0)
+ {
+ carry = m_v[i] + m_c[i] + h[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry;
+ m_v[i] = static_cast(carry);
+ carry >>= 8; i--; j--; k--;
+ }
+ while(i>=0 && j>=0)
+ {
+ carry = m_v[i] + m_c[i] + h[j] + carry;
+ m_v[i] = static_cast(carry);
+ carry >>= 8; i--; j--;
+ }
+ while (i>=0)
+ {
+ carry = m_v[i] + m_c[i] + carry;
+ m_v[i] = static_cast(carry);
+ carry >>= 8; i--;
+ }
+ }
+
+ m_reseed++;
+}
+
+// 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49)
+template
+void Hash_DRBG::Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2,
+ const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen)
+{
+ HASH hash;
+ byte counter = 1;
+ word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8));
+
+ size_t count;
+ for (count=0; outlen; outlen -= count, output += count, counter++)
+ {
+ hash.Update(&counter, 1);
+ hash.Update(reinterpret_cast(&bits), 4);
+
+ if (input1 && inlen1)
+ hash.Update(input1, inlen1);
+ if (input2 && inlen2)
+ hash.Update(input2, inlen2);
+ if (input3 && inlen3)
+ hash.Update(input3, inlen3);
+ if (input4 && inlen4)
+ hash.Update(input4, inlen4);
+
+ count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE);
+ hash.TruncatedFinal(output, count);
+ }
+}
+
+// *************************************************************
+
+// 10.1.2.3 Instantiation of HMAC_DRBG (p.45)
+template
+void HMAC_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength,
+ const byte* personalization, size_t personalizationLength)
+{
+ // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+ // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+ // personalization string during instantiation, or in the additional input during reseeding and generation,
+ // but this is not required and does not increase the "official" security strength of the DRBG
+ // instantiation that is recorded in the internal state.
+ CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+ if (entropyLength < MINIMUM_ENTROPY)
+ throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during instantiate");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+ CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE);
+ CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION);
+
+ std::fill(m_k.begin(), m_k.begin()+m_k.size(), byte(0));
+ std::fill(m_v.begin(), m_v.begin()+m_v.size(), byte(1));
+
+ HMAC_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength);
+ m_reseed = 1;
+}
+
+// 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46)
+template
+void HMAC_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)
+{
+ // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security
+ // strength of the instantiation. Additional entropy may be provided in the nonce or the optional
+ // personalization string during instantiation, or in the additional input during reseeding and generation,
+ // but this is not required and does not increase the "official" security strength of the DRBG
+ // instantiation that is recorded in the internal state..
+ CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY);
+ if (entropyLength < MINIMUM_ENTROPY)
+ throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during reseed");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY);
+ CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+ HMAC_Update(entropy, entropyLength, additional, additionaLength, NULL, 0);
+ m_reseed = 1;
+}
+
+// 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46)
+template
+void HMAC_DRBG::HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size)
+{
+ // Step 1
+ if (static_cast(m_reseed) >= static_cast(GetMaxRequestBeforeReseed()))
+ throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required");
+
+ if (size > GetMaxBytesPerRequest())
+ throw NIST_DRBG::Err("HMAC_DRBG", "Request size exceeds limit");
+
+ // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce,
+ // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds.
+ CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL);
+
+ // Step 2
+ if (additional && additionaLength)
+ HMAC_Update(additional, additionaLength, NULL, 0, NULL, 0);
+
+ // Step 3
+ HMAC hmac;
+ hmac.SetKey(m_k, m_k.size());
+
+ while (size)
+ {
+ hmac.Update(m_v, m_v.size());
+ hmac.TruncatedFinal(m_v, m_v.size());
+
+ size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE);
+ memcpy(output, m_v, count);
+
+ size -= count; output += count;
+ }
+
+ HMAC_Update(additional, additionaLength, NULL, 0, NULL, 0);
+ m_reseed++;
+}
+
+// 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44)
+template
+void HMAC_DRBG::HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3)
+{
+ const byte zero = 0, one = 1;
+ HMAC hmac;
+
+ // Step 1
+ hmac.SetKey(m_k, m_k.size());
+ hmac.Update(m_v, m_v.size());
+ hmac.Update(&zero, 1);
+
+ if (input1 && inlen1)
+ hmac.Update(input1, inlen1);
+ if (input2 && inlen2)
+ hmac.Update(input2, inlen2);
+ if (input3 && inlen3)
+ hmac.Update(input3, inlen3);
+
+ hmac.TruncatedFinal(m_k, m_k.size());
+
+ // Step 2
+ hmac.SetKey(m_k, m_k.size());
+ hmac.Update(m_v, m_v.size());
+
+ hmac.TruncatedFinal(m_v, m_v.size());
+
+ // Step 3
+ if ((inlen1 | inlen2 | inlen3) == 0)
+ return;
+
+ // Step 4
+ hmac.SetKey(m_k, m_k.size());
+ hmac.Update(m_v, m_v.size());
+ hmac.Update(&one, 1);
+
+ if (input1 && inlen1)
+ hmac.Update(input1, inlen1);
+ if (input2 && inlen2)
+ hmac.Update(input2, inlen2);
+ if (input3 && inlen3)
+ hmac.Update(input3, inlen3);
+
+ hmac.TruncatedFinal(m_k, m_k.size());
+
+ // Step 5
+ hmac.SetKey(m_k, m_k.size());
+ hmac.Update(m_v, m_v.size());
+
+ hmac.TruncatedFinal(m_v, m_v.size());
+}
+
NAMESPACE_END
#endif // CRYPTOPP_NIST_DRBG_H
diff --git a/secblock.h b/secblock.h
index 0fd17b28..11c3169a 100644
--- a/secblock.h
+++ b/secblock.h
@@ -498,13 +498,13 @@ public:
//! \details The elements are not initialized.
//! \note size is the count of elements, and not the number of bytes
explicit SecBlock(size_type size=0)
- : m_size(size), m_mark(SIZE_MAX/sizeof(T)), m_ptr(m_alloc.allocate(size, NULL)) { }
+ : m_mark(SIZE_MAX/sizeof(T)), m_size(size), m_ptr(m_alloc.allocate(size, NULL)) { }
//! \brief Copy construct a SecBlock from another SecBlock
//! \param t the other SecBlock
//! \throws std::bad_alloc
SecBlock(const SecBlock &t)
- : m_size(t.m_size), m_mark(t.m_mark), m_ptr(m_alloc.allocate(t.m_size, NULL)) {
+ : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULL)) {
CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size));
if (t.m_ptr) {memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));}
}
@@ -518,7 +518,7 @@ public:
//! Otherwise, the block is empty and not initialized.
//! \note size is the count of elements, and not the number of bytes
SecBlock(const T *ptr, size_type len)
- : m_size(len), m_mark(SIZE_MAX/sizeof(T)), m_ptr(m_alloc.allocate(len, NULL)) {
+ : m_mark(SIZE_MAX/sizeof(T)), m_size(len), m_ptr(m_alloc.allocate(len, NULL)) {
CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size));
if (ptr && m_ptr)
memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T));
@@ -797,14 +797,14 @@ public:
{
// Swap must occur on the allocator in case its FixedSize that spilled into the heap.
std::swap(m_alloc, b.m_alloc);
- std::swap(m_size, b.m_size);
std::swap(m_mark, b.m_mark);
+ std::swap(m_size, b.m_size);
std::swap(m_ptr, b.m_ptr);
}
// protected:
A m_alloc;
- size_type m_size, m_mark;
+ size_type m_mark, m_size;
T *m_ptr;
};
diff --git a/test.cpp b/test.cpp
index feaf51ce..6920048a 100644
--- a/test.cpp
+++ b/test.cpp
@@ -900,7 +900,7 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 0: result = ValidateAll(thorough); break;
case 1: result = TestSettings(); break;
case 2: result = TestOS_RNG(); break;
- case 3: result = TestNIST_DRBG(); break;
+// case 3: result = TestSecRandom(); break;
case 4: result = ValidateMD5(); break;
case 5: result = ValidateSHA(); break;
case 6: result = ValidateDES(); break;
@@ -974,6 +974,8 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 74: result = ValidateBLAKE2b(); break;
case 75: result = ValidatePoly1305(); break;
case 76: result = ValidateSipHash(); break;
+ case 77: result = ValidateHashDRBG(); break;
+ case 78: result = ValidateHmacDRBG(); break;
#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_IMPORTS)
// http://github.com/weidai11/cryptopp/issues/92
diff --git a/validat1.cpp b/validat1.cpp
index 724c5df9..0c8ca6f8 100644
--- a/validat1.cpp
+++ b/validat1.cpp
@@ -73,7 +73,7 @@ bool ValidateAll(bool thorough)
pass=TestOS_RNG() && pass;
pass=TestAutoSeeded() && pass;
pass=TestAutoSeededX917() && pass;
- pass=TestNIST_DRBG() && pass;
+ // pass=TestSecRandom() && pass;
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
pass=TestRDRAND() && pass;
@@ -105,6 +105,9 @@ bool ValidateAll(bool thorough)
pass=RunTestDataFile(CRYPTOPP_DATA_DIR "TestVectors/keccak.txt") && pass;
pass=RunTestDataFile(CRYPTOPP_DATA_DIR "TestVectors/sha3_fips_202.txt") && pass;
+ pass=ValidateHashDRBG() && pass;
+ pass=ValidateHmacDRBG() && pass;
+
pass=ValidateTiger() && pass;
pass=ValidateRIPEMD() && pass;
pass=ValidatePanama() && pass;
@@ -764,9 +767,9 @@ bool TestRDSEED()
}
#endif
-bool TestNIST_DRBG()
+bool ValidateHashDRBG()
{
- cout << "\nTesting NIST DRBG generators...\n\n";
+ cout << "\nTesting NIST Hash DRBGs...\n\n";
bool pass=true, fail;
// # CAVS 14.3
@@ -795,7 +798,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=0, E=16, N=8)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=0, E=16, N=8)\n";
}
{
@@ -820,7 +823,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=1, E=16, N=8)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (COUNT=1, E=16, N=8)\n";
}
{
@@ -848,7 +851,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16)\n";
}
{
@@ -876,7 +879,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16)\n";
}
{
@@ -902,7 +905,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=0, P=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=0, P=16)\n";
}
{
@@ -928,7 +931,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=0, P=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=0, P=16)\n";
}
{
@@ -957,7 +960,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16, P=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=0, E=16, N=8, A=16, P=16)\n";
}
{
@@ -986,7 +989,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 640/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16, P=16)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA1/128/440 (C0UNT=1, E=16, N=8, A=16, P=16)\n";
}
{
@@ -1018,7 +1021,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 1024/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=0, E=32, N=16, A=32, P=32)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=0, E=32, N=16, A=32, P=32)\n";
}
{
@@ -1050,7 +1053,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 1024/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=1, E=32, N=16, A=32, P=32)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/128/440 (C0UNT=1, E=32, N=16, A=32, P=32)\n";
}
{
@@ -1088,7 +1091,7 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 2048/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=0, E=32, N=16, A=32, P=32)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=0, E=32, N=16, A=32, P=32)\n";
}
{
@@ -1126,7 +1129,127 @@ bool TestNIST_DRBG()
fail = !!memcmp(result, expected, 2048/8);
pass = !fail && pass;
- cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=1, E=32, N=16, A=32, P=32)" << endl;
+ cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA512/256/888 (C0UNT=1, E=32, N=16, A=32, P=32)\n";
+ }
+
+ return pass;
+}
+
+bool ValidateHmacDRBG()
+{
+ cout << "\nTesting NIST HMAC DRBGs...\n\n";
+ bool pass=true, fail;
+
+ // # CAVS 14.3
+ // # DRBG800-90A information for "drbg_pr"
+ // # Generated on Tue Apr 02 15:32:12 2013
+
+ {
+ // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64]
+ // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640]
+ const byte entropy1[] = "\x79\x34\x9b\xbf\x7c\xdd\xa5\x79\x95\x57\x86\x66\x21\xc9\x13\x83";
+ const byte entropy2[] = "\xc7\x21\x5b\x5b\x96\xc4\x8e\x9b\x33\x8c\x74\xe3\xe9\x9d\xfe\xdf";
+ const byte nonce[] = "\x11\x46\x73\x3a\xbf\x8c\x35\xc8";
+
+ HMAC_DRBG drbg(entropy1, 16, nonce, 8);
+ drbg.IncorporateEntropy(entropy2, 16);
+
+ SecByteBlock result(80);
+ drbg.GenerateBlock(result, result.size());
+ drbg.GenerateBlock(result, result.size());
+
+ const byte expected[] = "\xc6\xa1\x6a\xb8\xd4\x20\x70\x6f\x0f\x34\xab\x7f\xec\x5a\xdc\xa9\xd8\xca\x3a\x13"
+ "\x3e\x15\x9c\xa6\xac\x43\xc6\xf8\xa2\xbe\x22\x83\x4a\x4c\x0a\x0a\xff\xb1\x0d\x71"
+ "\x94\xf1\xc1\xa5\xcf\x73\x22\xec\x1a\xe0\x96\x4e\xd4\xbf\x12\x27\x46\xe0\x87\xfd"
+ "\xb5\xb3\xe9\x1b\x34\x93\xd5\xbb\x98\xfa\xed\x49\xe8\x5f\x13\x0f\xc8\xa4\x59\xb7";
+
+ fail = !!memcmp(result, expected, 640/8);
+ pass = !fail && pass;
+
+ cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=0, E=16, N=8)\n";
+ }
+
+ {
+ // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64]
+ // [PersonalizationStringLen = 0], [AdditionalInputLen = 0], [ReturnedBitsLen = 640]
+ const byte entropy1[] = "\xee\x57\xfc\x23\x60\x0f\xb9\x02\x9a\x9e\xc6\xc8\x2e\x7b\x51\xe4";
+ const byte entropy2[] = "\x84\x1d\x27\x6c\xa9\x51\x90\x61\xd9\x2d\x7d\xdf\xa6\x62\x8c\xa3";
+ const byte nonce[] = "\x3e\x97\x21\xe4\x39\x3e\xf9\xad";
+
+ HMAC_DRBG drbg(entropy1, 16, nonce, 8);
+ drbg.IncorporateEntropy(entropy2, 16);
+
+ SecByteBlock result(80);
+ drbg.GenerateBlock(result, result.size());
+ drbg.GenerateBlock(result, result.size());
+
+ const byte expected[] = "\xee\x26\xa5\xc8\xef\x08\xa1\xca\x8f\x14\x15\x4d\x67\xc8\x8f\x5e\x7e\xd8\x21\x9d"
+ "\x93\x1b\x98\x42\xac\x00\x39\xf2\x14\x55\x39\xf2\x14\x2b\x44\x11\x7a\x99\x8c\x22"
+ "\xf5\x90\xf6\xc9\xb3\x8b\x46\x5b\x78\x3e\xcf\xf1\x3a\x77\x50\x20\x1f\x7e\xcf\x1b"
+ "\x8a\xb3\x93\x60\x4c\x73\xb2\x38\x93\x36\x60\x9a\xf3\x44\x0c\xde\x43\x29\x8b\x84";
+
+ fail = !!memcmp(result, expected, 640/8);
+ pass = !fail && pass;
+
+ cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=1, E=16, N=8)\n";
+ }
+
+ // *****************************************************
+
+ {
+ // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64]
+ // [PersonalizationStringLen = 0], [AdditionalInputLen = 16], [ReturnedBitsLen = 640]
+ const byte entropy1[] = "\x7d\x70\x52\xa7\x76\xfd\x2f\xb3\xd7\x19\x1f\x73\x33\x04\xee\x8b";
+ const byte entropy2[] = "\x49\x04\x7e\x87\x9d\x61\x09\x55\xee\xd9\x16\xe4\x06\x0e\x00\xc9";
+ const byte nonce[] = "\xbe\x4a\x0c\xee\xdc\xa8\x02\x07";
+ const byte additional1[] = "\xfd\x8b\xb3\x3a\xab\x2f\x6c\xdf\xbc\x54\x18\x11\x86\x1d\x51\x8d";
+ const byte additional2[] = "\x99\xaf\xe3\x47\x54\x04\x61\xdd\xf6\xab\xeb\x49\x1e\x07\x15\xb4";
+ const byte additional3[] = "\x02\xf7\x73\x48\x2d\xd7\xae\x66\xf7\x6e\x38\x15\x98\xa6\x4e\xf0";
+
+ HMAC_DRBG drbg(entropy1, 16, nonce, 8);
+ drbg.IncorporateEntropy(entropy2, 16, additional1, 16);
+
+ SecByteBlock result(80);
+ drbg.GenerateBlock(additional2, 16, result, result.size());
+ drbg.GenerateBlock(additional3, 16, result, result.size());
+
+ const byte expected[] = "\xa7\x36\x34\x38\x44\xfc\x92\x51\x13\x91\xdb\x0a\xdd\xd9\x06\x4d\xbe\xe2\x4c\x89"
+ "\x76\xaa\x25\x9a\x9e\x3b\x63\x68\xaa\x6d\xe4\xc9\xbf\x3a\x0e\xff\xcd\xa9\xcb\x0e"
+ "\x9d\xc3\x36\x52\xab\x58\xec\xb7\x65\x0e\xd8\x04\x67\xf7\x6a\x84\x9f\xb1\xcf\xc1"
+ "\xed\x0a\x09\xf7\x15\x50\x86\x06\x4d\xb3\x24\xb1\xe1\x24\xf3\xfc\x9e\x61\x4f\xcb";
+
+ fail = !!memcmp(result, expected, 640/8);
+ pass = !fail && pass;
+
+ cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=0, E=16, N=8, A=16)\n";
+ }
+
+ {
+ // [SHA-1], [PredictionResistance = False], [EntropyInputLen = 128], [NonceLen = 64]
+ // [PersonalizationStringLen = 0], [AdditionalInputLen = 16], [ReturnedBitsLen = 640]
+ const byte entropy1[] = "\x29\xc6\x2a\xfa\x3c\x52\x20\x8a\x3f\xde\xcb\x43\xfa\x61\x3f\x15";
+ const byte entropy2[] = "\xbd\x87\xbe\x99\xd1\x84\x16\x54\x12\x31\x41\x40\xd4\x02\x71\x41";
+ const byte nonce[] = "\x6c\x9e\xb5\x9a\xc3\xc2\xd4\x8b";
+ const byte additional1[] = "\x43\x3d\xda\xf2\x59\xd1\x4b\xcf\x89\x76\x30\xcc\xaa\x27\x33\x8c";
+ const byte additional2[] = "\x14\x11\x46\xd4\x04\xf2\x84\xc2\xd0\x2b\x6a\x10\x15\x6e\x33\x82";
+ const byte additional3[] = "\xed\xc3\x43\xdb\xff\xe7\x1a\xb4\x11\x4a\xc3\x63\x9d\x44\x5b\x65";
+
+ HMAC_DRBG drbg(entropy1, 16, nonce, 8);
+ drbg.IncorporateEntropy(entropy2, 16, additional1, 16);
+
+ SecByteBlock result(80);
+ drbg.GenerateBlock(additional2, 16, result, result.size());
+ drbg.GenerateBlock(additional3, 16, result, result.size());
+
+ const byte expected[] = "\x8c\x73\x0f\x05\x26\x69\x4d\x5a\x9a\x45\xdb\xab\x05\x7a\x19\x75\x35\x7d\x65\xaf"
+ "\xd3\xef\xf3\x03\x32\x0b\xd1\x40\x61\xf9\xad\x38\x75\x91\x02\xb6\xc6\x01\x16\xf6"
+ "\xdb\x7a\x6e\x8e\x7a\xb9\x4c\x05\x50\x0b\x4d\x1e\x35\x7d\xf8\xe9\x57\xac\x89\x37"
+ "\xb0\x5f\xb3\xd0\x80\xa0\xf9\x06\x74\xd4\x4d\xe1\xbd\x6f\x94\xd2\x95\xc4\x51\x9d";
+
+ fail = !!memcmp(result, expected, 640/8);
+ pass = !fail && pass;
+
+ cout << (fail ? "FAILED " : "passed ") << "HMAC_DRBG SHA1/128/440 (COUNT=1, E=16, N=8, A=16)\n";
}
return pass;
diff --git a/validate.h b/validate.h
index 860db6ca..ffdb2a90 100644
--- a/validate.h
+++ b/validate.h
@@ -8,7 +8,7 @@
bool ValidateAll(bool thorough);
bool TestSettings();
bool TestOS_RNG();
-bool TestNIST_DRBG();
+// bool TestSecRandom();
bool TestAutoSeeded();
bool TestAutoSeededX917();
@@ -94,6 +94,9 @@ bool ValidateECDSA();
bool ValidateECGDSA();
bool ValidateESIGN();
+bool ValidateHashDRBG();
+bool ValidateHmacDRBG();
+
#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_IMPORTS)
// http://github.com/weidai11/cryptopp/issues/92
bool TestSecBlock();