// drbg.h - written and placed in public domain by Jeffrey Walton. /// \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) /// \since Crypto++ 6.0 #ifndef CRYPTOPP_NIST_DRBG_H #define CRYPTOPP_NIST_DRBG_H #include "cryptlib.h" #include "secblock.h" #include "hmac.h" #include "sha.h" 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) /// \details You should reseed the generator after a fork() to avoid multiple generators /// with the same internal state. /// \sa Recommendation /// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) /// \since Crypto++ 6.0 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() {} /// \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 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 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 SecurityStrength() 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 SeedLength() 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 MinEntropyLength() 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 MaxEntropyLength() 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 MinNonceLength() 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 MaxNonceLength() 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 MaxBytesPerRequest() 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 MaxRequestBeforeReseed() 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_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; }; // ************************************************************* /// \tparam HASH NIST approved hash derived from HashTransformation /// \tparam STRENGTH security strength, in bytes /// \tparam SEEDLENGTH seed length, in bytes /// \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 INT_MAX due /// to the limited data range of an int. /// \details You should reseed the generator after a fork() to avoid multiple generators /// with the same internal state. /// \sa Recommendation /// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) /// \since Crypto++ 6.0 template 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); static std::string StaticAlgorithmName() { return std::string("Hash_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } /// \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=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH), m_reseed(0) { if (m_c.data()) // GCC analyzer warning std::memset(m_c.data(), 0x00, m_c.size()); if (m_v.data()) // GCC analyzer warning std::memset(m_v.data(), 0x00, m_v.size()); if (entropy != NULLPTR && entropyLength != 0) DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); } unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} unsigned int SeedLength() const {return SEED_LENGTH;} unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} unsigned int MinNonceLength() const {return MINIMUM_NONCE;} unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} void IncorporateEntropy(const byte *input, size_t length) {return DRBG_Reseed(input, length, NULLPTR, 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 Hash_Generate(NULLPTR, 0, output, size);} void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) {return Hash_Generate(additional, additionaLength, output, size);} std::string AlgorithmProvider() const {/*Hack*/HASH hash; return hash.AlgorithmProvider();} protected: // 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); // 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); // 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); // 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: HASH m_hash; SecByteBlock m_c, m_v, m_temp; 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; // ************************************************************* /// \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 HMAC 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. /// \details You should reseed the generator after a fork() to avoid multiple generators /// with the same internal state. /// \sa Recommendation /// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) /// \since Crypto++ 6.0 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); static std::string StaticAlgorithmName() { return std::string("HMAC_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } /// \brief Construct a HMAC 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=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE), m_reseed(0) { if (m_k.data()) // GCC analyzer warning std::memset(m_k, 0x00, m_k.size()); if (m_v.data()) // GCC analyzer warning std::memset(m_v, 0x00, m_v.size()); if (entropy != NULLPTR && entropyLength != 0) DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); } unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} unsigned int SeedLength() const {return SEED_LENGTH;} unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} unsigned int MinNonceLength() const {return MINIMUM_NONCE;} unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} void IncorporateEntropy(const byte *input, size_t length) {return DRBG_Reseed(input, length, NULLPTR, 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(NULLPTR, 0, output, size);} void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) {return HMAC_Generate(additional, additionaLength, output, size);} std::string AlgorithmProvider() const {/*Hack*/HASH hash; return hash.AlgorithmProvider();} 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: HMAC m_hmac; 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, NULLPTR, 0, t1, t1.size()); Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 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(), NULLPTR, 0, NULLPTR, 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(MaxRequestBeforeReseed())) throw NIST_DRBG::Err("Hash_DRBG", "Reseed required"); if (size > MaxBytesPerRequest()) 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) { const byte two = 2; m_temp.New(HASH::DIGESTSIZE); m_hash.Update(&two, 1); m_hash.Update(m_v, m_v.size()); m_hash.Update(additional, additionaLength); m_hash.Final(m_temp); CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); int carry=0, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; while (j>=0) { carry = m_v[i] + m_temp[j] + carry; m_v[i] = static_cast(carry); i--; j--; carry >>= 8; } while (i>=0) { carry = m_v[i] + carry; m_v[i] = static_cast(carry); i--; carry >>= 8; } } // Step 3 { m_temp.Assign(m_v); while (size) { m_hash.Update(m_temp, m_temp.size()); size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); m_hash.TruncatedFinal(output, count); IncrementCounterByOne(m_temp, static_cast(m_temp.size())); size -= count; output += count; } } // Steps 4-7 { const byte three = 3; m_temp.New(HASH::DIGESTSIZE); m_hash.Update(&three, 1); m_hash.Update(m_v, m_v.size()); m_hash.Final(m_temp); CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed)); int carry=0, k=sizeof(m_reseed)-1, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; while (k>=0) { carry = m_v[i] + m_c[i] + m_temp[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry; m_v[i] = static_cast(carry); i--; j--; k--; carry >>= 8; } while (j>=0) { carry = m_v[i] + m_c[i] + m_temp[j] + carry; m_v[i] = static_cast(carry); i--; j--; carry >>= 8; } while (i>=0) { carry = m_v[i] + m_c[i] + carry; m_v[i] = static_cast(carry); i--; carry >>= 8; } } 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) { byte counter = 1; word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8)); while (outlen) { m_hash.Update(&counter, 1); m_hash.Update(reinterpret_cast(&bits), 4); if (input1 && inlen1) m_hash.Update(input1, inlen1); if (input2 && inlen2) m_hash.Update(input2, inlen2); if (input3 && inlen3) m_hash.Update(input3, inlen3); if (input4 && inlen4) m_hash.Update(input4, inlen4); size_t count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE); m_hash.TruncatedFinal(output, count); output += count; outlen -= count; counter++; } } // ************************************************************* // 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, NULLPTR, 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(MaxRequestBeforeReseed())) throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required"); if (size > MaxBytesPerRequest()) 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, NULLPTR, 0, NULLPTR, 0); // Step 3 m_hmac.SetKey(m_k, m_k.size()); while (size) { m_hmac.Update(m_v, m_v.size()); m_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, NULLPTR, 0, NULLPTR, 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; // Step 1 m_hmac.SetKey(m_k, m_k.size()); m_hmac.Update(m_v, m_v.size()); m_hmac.Update(&zero, 1); if (input1 && inlen1) m_hmac.Update(input1, inlen1); if (input2 && inlen2) m_hmac.Update(input2, inlen2); if (input3 && inlen3) m_hmac.Update(input3, inlen3); m_hmac.TruncatedFinal(m_k, m_k.size()); // Step 2 m_hmac.SetKey(m_k, m_k.size()); m_hmac.Update(m_v, m_v.size()); m_hmac.TruncatedFinal(m_v, m_v.size()); // Step 3 if ((inlen1 | inlen2 | inlen3) == 0) return; // Step 4 m_hmac.SetKey(m_k, m_k.size()); m_hmac.Update(m_v, m_v.size()); m_hmac.Update(&one, 1); if (input1 && inlen1) m_hmac.Update(input1, inlen1); if (input2 && inlen2) m_hmac.Update(input2, inlen2); if (input3 && inlen3) m_hmac.Update(input3, inlen3); m_hmac.TruncatedFinal(m_k, m_k.size()); // Step 5 m_hmac.SetKey(m_k, m_k.size()); m_hmac.Update(m_v, m_v.size()); m_hmac.TruncatedFinal(m_v, m_v.size()); } NAMESPACE_END #endif // CRYPTOPP_NIST_DRBG_H