diff --git a/drbg.h b/drbg.h index 4020ba84..81694a94 100644 --- a/drbg.h +++ b/drbg.h @@ -4,8 +4,7 @@ //! \file drbg.h //! \brief Classes for NIST DRBGs from SP 800-90A //! \sa Recommendation -//! for Random Number Generation Using Deterministic Random Bit Generators, -//! Rev 1 (June 2015) +//! for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) //! \since Crypto++ 5.7 #ifndef CRYPTOPP_NIST_DRBG_H @@ -20,11 +19,19 @@ NAMESPACE_BEGIN(CryptoPP) //! \brief Interface for NIST DRBGs from SP 800-90A //! \details NIST_DRBG is the base class interface for NIST DRBGs from SP 800-90A Rev 1 (June 2015) //! \sa Recommendation -//! for Random Number Generation Using Deterministic Random Bit Generators, -//! Rev 1 (June 2015) +//! for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) //! \since Crypto++ 5.7 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) {} + }; + public: virtual ~NIST_DRBG() {} @@ -36,33 +43,39 @@ public: //! \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 requirements. + //! 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 entropy to add to the generator - //! \param additionaLength the size of the additional entropy 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 input must meet NIST - //! SP 800-90B requirements. + //! 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 additional additional entropy to add to the generator - //! \param additionaLength the size of the additional entropy buffer + //! \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 - //! \details GenerateBlock() is an overload provided to match NIST requirements. The byte array for additional is optional. If present + //! \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; @@ -81,7 +94,7 @@ public: //! \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 requirements. + //! HREF="http://csrc.nist.gov/publications/PubsSPs.html">NIST SP 800-90C requirements. virtual unsigned int GetMinEntropy() const=0; //! \brief Provides the maximum entropy @@ -140,7 +153,7 @@ public: CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH) CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH) CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH) - CRYPTOPP_CONSTANT(MINIMUM_NONCE=STRENGTH/2) + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0) CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0) CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0) CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=UINT_MAX) @@ -153,32 +166,30 @@ public: //! \brief Construct a Hash DRBG //! \param entropy the entropy to instantiate the generator //! \param entropyLength the size of the entropy buffer - //! \param nonce additional entropy to instantiate the generator + //! \param nonce additional input to instantiate the generator //! \param nonceLength the size of the nonce buffer - //! \param personalization additional entropy to instantiate the generator - //! \param personalizationLength the size of the additional buffer + //! \param personalization additional input to instantiate the generator + //! \param personalizationLength the size of the additional input 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 requirements. + //! SP 800-90C requirements. //! \details The nonce and personalization are optional byte arrays. If nonce is supplied, then it should include MINIMUM_NONCE bytes of entropy. - //! \details NIST instantiation requirements demand the generator is constructed with at least MINIMUM_ENTROPY entropy. - //! The generator has the same requirements during reseed operations. //! \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. + //! requirements of NIST 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);
+	//!    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) { - CRYPTOPP_ASSERT(entropyLength + nonceLength/2 >= GetMinEntropy()); DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); } @@ -236,7 +247,20 @@ protected: void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength) { - CRYPTOPP_ASSERT(entropyLength+nonceLength+personalizationLength >= GetMinEntropy()); + // 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); @@ -250,6 +274,20 @@ protected: // 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) { + // 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()); @@ -264,7 +302,14 @@ protected: { // Step 1 if (static_cast(m_reseed) >= static_cast(GetMaxRequestBeforeReseed())) - throw Exception(Exception::OTHER_ERROR, "Reseed required"); + 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) diff --git a/trap.h b/trap.h index 541532e3..91f6e836 100644 --- a/trap.h +++ b/trap.h @@ -40,7 +40,7 @@ //! CRYPTOPP_ASSERT is only in effect when the user explicitly requests a debug configuration. //! \details If you want to ensure CRYPTOPP_ASSERT is inert, then do not define //! CRYPTOPP_DEBUG, DEBUG or _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT -//! is processed into ((void)(exp)). +//! is preprocessed into an empty string. //! \details The traditional Posix define NDEBUG has no effect on CRYPTOPP_DEBUG, CRYPTOPP_ASSERT //! or DebugTrapHandler. //! \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and DebugTrapHandler is shown below. The library's @@ -89,7 +89,7 @@ // Remove CRYPTOPP_ASSERT in non-debug builds. // Can't use CRYPTOPP_UNUSED due to circular dependency #ifndef CRYPTOPP_ASSERT -# define CRYPTOPP_ASSERT(exp) ((void)0) +# define CRYPTOPP_ASSERT(exp) #endif NAMESPACE_BEGIN(CryptoPP) diff --git a/validat1.cpp b/validat1.cpp index 2532a211..39429d02 100644 --- a/validat1.cpp +++ b/validat1.cpp @@ -986,7 +986,7 @@ bool TestNIST_DRBG() const byte additional2[] = "\x77\xfd\x1d\x68\xd6\xa4\xdd\xd5\xf3\x27\x25\x2d\x3f\x6b\xdf\xee\x8c\x35\xce\xd3\x83\xbe\xaf\xc9\x32\x77\xef\xf2\x1b\x6f\xf4\x1b"; const byte additional3[] = "\x59\xa0\x1f\xf8\x6a\x58\x72\x1e\x85\xd2\xf8\x3f\x73\x99\xf1\x96\x4e\x27\xf8\x7f\xcd\x1b\xf5\xc1\xeb\xf3\x37\x10\x9b\x13\xbd\x24"; - Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); drbg.IncorporateEntropy(entropy2, 32, additional1, 32); SecByteBlock result(128); @@ -1004,7 +1004,7 @@ bool TestNIST_DRBG() fail = !!memcmp(result, expected, 1024/8); pass = !fail && pass; - cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/256/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)" << endl; } { @@ -1018,7 +1018,7 @@ bool TestNIST_DRBG() const byte additional2[] = "\xaf\x25\xc4\x6e\x21\xfc\xc3\xaf\x1f\xbb\xf8\x76\xb4\x57\xab\x1a\x94\x0a\x85\x16\x47\x81\xa4\xab\xda\xc8\xab\xca\xd0\x84\xda\xae"; const byte additional3[] = "\x59\x5b\x44\x94\x38\x86\x36\xff\x8e\x45\x1a\x0c\x42\xc8\xcc\x21\x06\x38\x3a\xc5\xa6\x30\x96\xb9\x14\x81\xb3\xa1\x2b\xc8\xcd\xf6"; - Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); + Hash_DRBG drbg(entropy1, 32, nonce, 16, personalization, 32); drbg.IncorporateEntropy(entropy2, 32, additional1, 32); SecByteBlock result(128); @@ -1036,7 +1036,7 @@ bool TestNIST_DRBG() fail = !!memcmp(result, expected, 1024/8); pass = !fail && pass; - cout << (fail ? "FAILED " : "passed ") << "Hash_DRBG SHA256/256/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)" << endl; } {