diff --git a/drbg.h b/drbg.h index 20475db7..4020ba84 100644 --- a/drbg.h +++ b/drbg.h @@ -2,46 +2,118 @@ // Copyright assigned to Crypto++ project. //! \file drbg.h -//! \brief Classes for NIST DRBGs from 800-90A Rev 1 (June 2015) +//! \brief Classes for NIST DRBGs from SP 800-90A //! \sa Recommendation -//! for Random Number Generation Using Deterministic Random Bit Generators +//! for Random Number Generation Using Deterministic Random Bit Generators, +//! Rev 1 (June 2015) //! \since Crypto++ 5.7 -#ifndef CRYPTOPP_NIST_DETERMINISTIC_RANDOM_BIT_GENERATORS_H -#define CRYPTOPP_NIST_DETERMINISTIC_RANDOM_BIT_GENERATORS_H +#ifndef CRYPTOPP_NIST_DRBG_H +#define CRYPTOPP_NIST_DRBG_H #include "cryptlib.h" #include "secblock.h" NAMESPACE_BEGIN(CryptoPP) +//! \class NIST_DRBG +//! \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) +//! \since Crypto++ 5.7 class NIST_DRBG : public RandomNumberGenerator { public: virtual ~NIST_DRBG() {} - // RandomNumberGenerator + //! \brief Determines if a generator can accept additional entropy + //! \return true + //! \details All NIST_DRBG return true virtual bool CanIncorporateEntropy() const {return true;} - // RandomNumberGenerator + + //! \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 + //! \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. virtual void IncorporateEntropy(const byte *input, size_t length)=0; - // RandomNumberGenerator NIST overload + + //! \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 + //! \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. virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; - // RandomNumberGenerator + + //! \brief Generate random array of bytes + //! \param output the byte buffer + //! \param size the length of the buffer, in bytes virtual void GenerateBlock(byte *output, size_t size)=0; - // RandomNumberGenerator NIST overload + + //! \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 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 + //! 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 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 + //! \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. virtual unsigned int GetMinEntropy() const=0; + + //! \brief Provides the maximum entropy + //! \returns The maximum entropy size that can be consumed by the generator, in bytes + //! \details The equivalent class constant is MAXIMUM_ENTROPY. MAXIMUM_ENTROPY has been reduced + //! from 235 to UINT_MAX to fit the C++ unsigned int datatype. virtual unsigned int GetMaxEntropy() const=0; - virtual unsigned int GetMaxRequest() const=0; - virtual unsigned int GetMaxReseed() const=0; + + //! \brief Provides the minimum nonce + //! \returns The minimum nonce size recommended for the generator, in bytes + //! \details The equivalent class constant is MINIMUM_NONCE. The nonce is optional but recommended + virtual unsigned int GetMinNonce() const=0; + + //! \brief Provides the maximum nonce + //! \returns The maximum nonce that can be consumed by the generator, in bytes + //! \details The equivalent class constant is MAXIMUM_NONCE. The nonce is optional but recommended. + //! MAXIMUM_NONCE has been reduced from 235 to UINT_MAX to fit the C++ unsigned int datatype. + 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 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 + 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* persoanlization, size_t personalizationLength)=0; + 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; }; @@ -50,13 +122,16 @@ protected: //! \tparam HASH NIST approved hash derived from HashTransformation //! \tparam STRENGTH security strength, in bytes //! \tparam SEEDLENGTH seed length, in bytes -//! \brief Classes for NIST DRBGs from 800-90A Rev 1 (June 2015) +//! \brief Hash_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, Hash_DRBG limits it to UINT_MAX due to the limited data range of an unsigned int. //! \sa Recommendation -//! for Random Number Generation Using Deterministic Random Bit Generators +//! for Random Number Generation Using Deterministic Random Bit Generators, +//! Rev 1 (June 2015) //! \since Crypto++ 5.7 template class Hash_DRBG : public NIST_DRBG @@ -65,20 +140,56 @@ 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_ADDITIONAL=0) + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0) + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=UINT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=UINT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=UINT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=UINT_MAX) + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536) + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=UINT_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 entropy 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 + //! \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. + //! \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. + //! 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* persoanlization=NULL, size_t persoanlizationLength=0) + 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, persoanlization, persoanlizationLength); + CRYPTOPP_ASSERT(entropyLength + nonceLength/2 >= GetMinEntropy()); + 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 SECURITY_STRENGTH;} - unsigned int GetMaxEntropy() const {return (unsigned int)STDMIN((word64)UINT_MAX, W64LIT(4294967296));} - unsigned int GetMaxRequest() const {return 65536;} // 2^16 bytes per request - unsigned int GetMaxReseed() const {return (unsigned int)STDMIN((word64)UINT_MAX, W64LIT(35184372088832));} + unsigned int GetMinEntropy() const {return MINIMUM_ENTROPY;} + unsigned int GetMaxEntropy() const {return static_cast(MAXIMUM_ENTROPY);} + unsigned int GetMinNonce() const {return MINIMUM_NONCE;} + unsigned int GetMaxNonce() const {return static_cast(MAXIMUM_NONCE);} + unsigned int GetMaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} // 2^16 bytes per request + unsigned int GetMaxRequestBeforeReseed() const {return static_cast(MAXIMUM_REQUESTS_BEFORE_RESEED);} void IncorporateEntropy(const byte *input, size_t length) {return DRBG_Reseed(input, length, NULL, 0);} @@ -123,13 +234,13 @@ protected: // 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* persoanlization, size_t persoanlizationLength) + const byte* personalization, size_t personalizationLength) { - CRYPTOPP_ASSERT(entropyLength+nonceLength+persoanlizationLength >= GetMinEntropy()); + CRYPTOPP_ASSERT(entropyLength+nonceLength+personalizationLength >= GetMinEntropy()); const byte zero = 0; SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); - Hash_df(entropy, entropyLength, nonce, nonceLength, persoanlization, persoanlizationLength, NULL, 0, t1, t1.size()); + 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); @@ -152,7 +263,7 @@ protected: void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) { // Step 1 - if (static_cast(m_reseed) >= static_cast(GetMaxReseed())) + if (static_cast(m_reseed) >= static_cast(GetMaxRequestBeforeReseed())) throw Exception(Exception::OTHER_ERROR, "Reseed required"); // Step 2 @@ -242,4 +353,5 @@ private: NAMESPACE_END -#endif // CRYPTOPP_NIST_DETERMINISTIC_RANDOM_BIT_GENERATORS_H +#endif // CRYPTOPP_NIST_DRBG_H +