diff --git a/drbg.h b/drbg.h index a146019a..0feae035 100644 --- a/drbg.h +++ b/drbg.h @@ -24,120 +24,122 @@ NAMESPACE_BEGIN(CryptoPP) class NIST_DRBG : public RandomNumberGenerator { public: - //! \brief Exception thrown when a NIST DRBG encounters an error - class Err : public Exception - { - public: - explicit Err(const std::string &c, const std::string &m) - : Exception(OTHER_ERROR, c + ": " + m) {} - }; + //! \brief Exception thrown when a NIST DRBG encounters an error + class Err : public Exception + { + public: + explicit Err(const std::string &c, const std::string &m) + : Exception(OTHER_ERROR, c + ": " + m) {} + }; public: - virtual ~NIST_DRBG() {} + virtual ~NIST_DRBG() {} - //! \brief Determines if a generator can accept additional entropy - //! \return true - //! \details All NIST_DRBG return true - virtual bool CanIncorporateEntropy() const {return true;} + //! \brief Determines if a generator can accept additional entropy + //! \return true + //! \details All NIST_DRBG return true + virtual bool CanIncorporateEntropy() const {return true;} - //! \brief Update RNG state with additional unpredictable values - //! \param input the entropy to add to the generator - //! \param length the size of the input buffer - //! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy - //! \details NIST instantiation and reseed requirements demand the generator is constructed with at least MINIMUM_ENTROPY - //! entropy. The byte array for input must meet NIST - //! SP 800-90B or SP 800-90C requirements. - virtual void IncorporateEntropy(const byte *input, size_t length)=0; + //! \brief Update RNG state with additional unpredictable values + //! \param input the entropy to add to the generator + //! \param length the size of the input buffer + //! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy + //! \details NIST instantiation and reseed requirements demand the generator is constructed with at least MINIMUM_ENTROPY + //! entropy. The byte array for input must meet NIST + //! SP 800-90B or SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *input, size_t length)=0; - //! \brief Update RNG state with additional unpredictable values - //! \param entropy the entropy to add to the generator - //! \param entropyLength the size of the input buffer - //! \param additional additional input to add to the generator - //! \param additionaLength the size of the additional input buffer - //! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy - //! \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST instantiation and - //! reseed requirements demand the generator is constructed with at least MINIMUM_ENTROPY entropy. - //! The byte array for entropy must meet NIST - //! SP 800-90B or SP 800-90C requirements. - virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; + //! \brief Update RNG state with additional unpredictable values + //! \param entropy the entropy to add to the generator + //! \param entropyLength the size of the input buffer + //! \param additional additional input to add to the generator + //! \param additionaLength the size of the additional input buffer + //! \throws NIST_DRBG::Err if the generator is reseeded with insufficient entropy + //! \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST instantiation and + //! reseed requirements demand the generator is constructed with at least MINIMUM_ENTROPY entropy. + //! The byte array for entropy must meet NIST + //! SP 800-90B or SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; - //! \brief Generate random array of bytes - //! \param output the byte buffer - //! \param size the length of the buffer, in bytes - //! \throws NIST_DRBG::Err if a reseed is required - //! \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST - virtual void GenerateBlock(byte *output, size_t size)=0; + //! \brief Generate random array of bytes + //! \param output the byte buffer + //! \param size the length of the buffer, in bytes + //! \throws NIST_DRBG::Err if a reseed is required + //! \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + virtual void GenerateBlock(byte *output, size_t size)=0; - //! \brief Generate random array of bytes - //! \param additional additional input to add to the generator - //! \param additionaLength the size of the additional input buffer - //! \param output the byte buffer - //! \param size the length of the buffer, in bytes - //! \throws NIST_DRBG::Err if a reseed is required - //! \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST - //! \details GenerateBlock() is an overload provided to match NIST requirements. The byte array for additional - //! input is optional. If present the additional randomness is mixed before generating the output bytes. - virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0; + //! \brief Generate random array of bytes + //! \param additional additional input to add to the generator + //! \param additionaLength the size of the additional input buffer + //! \param output the byte buffer + //! \param size the length of the buffer, in bytes + //! \throws NIST_DRBG::Err if a reseed is required + //! \throws NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + //! \details GenerateBlock() is an overload provided to match NIST requirements. The byte array for additional + //! input is optional. If present the additional randomness is mixed before generating the output bytes. + virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0; - //! \brief Provides the security strength - //! \returns The security strength of the generator, in bytes - //! \details The equivalent class constant is SECURITY_STRENGTH - virtual unsigned int GetSecurityStrength() const=0; + //! \brief Provides the security strength + //! \returns The security strength of the generator, in bytes + //! \details The equivalent class constant is SECURITY_STRENGTH + virtual unsigned int GetSecurityStrength() const=0; - //! \brief Provides the seed length - //! \returns The seed size of the generator, in bytes - //! \details The equivalent class constant is SEED_LENGTH. The size is - //! used to maintain internal state of V and C. - virtual unsigned int GetSeedLength() const=0; + //! \brief Provides the seed length + //! \returns The seed size of the generator, in bytes + //! \details The equivalent class constant is SEED_LENGTH. The size is + //! used to maintain internal state of V and C. + virtual unsigned int GetSeedLength() const=0; - //! \brief Provides the minimum entropy size - //! \returns The minimum entropy size required by the generator, in bytes - //! \details The equivalent class constant is MINIMUM_ENTROPY. All NIST DRBGs must be instaniated with at least - //! MINIMUM_ENTROPY bytes of entropy. The bytes must meet NIST SP 800-90B or SP 800-90C requirements. - virtual unsigned int GetMinEntropy() const=0; + //! \brief Provides the minimum entropy size + //! \returns The minimum entropy size required by the generator, in bytes + //! \details The equivalent class constant is MINIMUM_ENTROPY. All NIST DRBGs must be instaniated with at least + //! MINIMUM_ENTROPY bytes of entropy. The bytes must meet NIST SP 800-90B or SP 800-90C requirements. + virtual unsigned int GetMinEntropy() const=0; - //! \brief Provides the maximum entropy size - //! \returns The maximum entropy size that can be consumed by the generator, in bytes - //! \details The equivalent class constant is MAXIMUM_ENTROPY. The bytes must meet NIST SP 800-90B or SP 800-90C requirements. - //! MAXIMUM_ENTROPY has been reduced from 235 to INT_MAX to fit the underlying C++ datatype. - virtual unsigned int GetMaxEntropy() const=0; + //! \brief Provides the maximum entropy size + //! \returns The maximum entropy size that can be consumed by the generator, in bytes + //! \details The equivalent class constant is MAXIMUM_ENTROPY. The bytes must meet NIST SP 800-90B or SP 800-90C requirements. + //! MAXIMUM_ENTROPY has been reduced from 235 to INT_MAX to fit the underlying C++ datatype. + virtual unsigned int GetMaxEntropy() const=0; - //! \brief Provides the minimum nonce size - //! \returns The minimum nonce size recommended for the generator, in bytes - //! \details The equivalent class constant is MINIMUM_NONCE. If a nonce is not required then - //! MINIMUM_NONCE is 0. Hash_DRBG does not require a nonce, while HMAC_DRBG - //! and CTR_DRBG require a nonce. - virtual unsigned int GetMinNonce() const=0; + //! \brief Provides the minimum nonce size + //! \returns The minimum nonce size recommended for the generator, in bytes + //! \details The equivalent class constant is MINIMUM_NONCE. If a nonce is not required then + //! MINIMUM_NONCE is 0. Hash_DRBG does not require a nonce, while HMAC_DRBG + //! and CTR_DRBG require a nonce. + virtual unsigned int GetMinNonce() const=0; - //! \brief Provides the maximum nonce size - //! \returns The maximum nonce that can be consumed by the generator, in bytes - //! \details The equivalent class constant is MAXIMUM_NONCE. MAXIMUM_NONCE has been reduced from - //! 235 to INT_MAX to fit the underlying C++ datatype. If a nonce is not required then - //! MINIMUM_NONCE is 0. Hash_DRBG does not require a nonce, while HMAC_DRBG - //! and CTR_DRBG require a nonce. - virtual unsigned int GetMaxNonce() const=0; + //! \brief Provides the maximum nonce size + //! \returns The maximum nonce that can be consumed by the generator, in bytes + //! \details The equivalent class constant is MAXIMUM_NONCE. MAXIMUM_NONCE has been reduced from + //! 235 to INT_MAX to fit the underlying C++ datatype. If a nonce is not required then + //! MINIMUM_NONCE is 0. Hash_DRBG does not require a nonce, while HMAC_DRBG + //! and CTR_DRBG require a nonce. + virtual unsigned int GetMaxNonce() const=0; - //! \brief Provides the maximum size of a request to GenerateBlock - //! \returns The the maximum size of a request to GenerateBlock(), in bytes - //! \details The equivalent class constant is MAXIMUM_BYTES_PER_REQUEST - virtual unsigned int GetMaxBytesPerRequest() const=0; + //! \brief Provides the maximum size of a request to GenerateBlock + //! \returns The the maximum size of a request to GenerateBlock(), in bytes + //! \details The equivalent class constant is MAXIMUM_BYTES_PER_REQUEST + virtual unsigned int GetMaxBytesPerRequest() const=0; - //! \brief Provides the maximum number of requests before a reseed - //! \returns The the maximum number of requests before a reseed, in bytes - //! \details The equivalent class constant is MAXIMUM_REQUESTS_BEFORE_RESEED. - //! MAXIMUM_REQUESTS_BEFORE_RESEED has been reduced from 248 to INT_MAX - //! to fit the underlying C++ datatype. - virtual unsigned int GetMaxRequestBeforeReseed() const=0; + //! \brief Provides the maximum number of requests before a reseed + //! \returns The the maximum number of requests before a reseed, in bytes + //! \details The equivalent class constant is MAXIMUM_REQUESTS_BEFORE_RESEED. + //! MAXIMUM_REQUESTS_BEFORE_RESEED has been reduced from 248 to INT_MAX + //! to fit the underlying C++ datatype. + virtual unsigned int GetMaxRequestBeforeReseed() const=0; protected: - virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength, - const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0; + virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength, + const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0; - virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; + virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; }; +// ************************************************************* + //! \class Hash_DRBG //! \tparam HASH NIST approved hash derived from HashTransformation //! \tparam STRENGTH security strength, in bytes @@ -153,257 +155,533 @@ protected: //! for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) //! \since Crypto++ 5.7 template -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();