aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/entropy/entropy_src.h5
-rw-r--r--src/lib/ffi/ffi.cpp2
-rw-r--r--src/lib/prov/pkcs11/p11_randomgenerator.h4
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.cpp2
-rw-r--r--src/lib/rng/auto_rng.h47
-rw-r--r--src/lib/rng/auto_rng/auto_rng.cpp116
-rw-r--r--src/lib/rng/auto_rng/auto_rng.h67
-rw-r--r--src/lib/rng/auto_rng/info.txt1
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.cpp99
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h68
-rw-r--r--src/lib/rng/hmac_drbg/info.txt1
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp86
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.h70
-rw-r--r--src/lib/rng/hmac_rng/info.txt1
-rw-r--r--src/lib/rng/info.txt2
-rw-r--r--src/lib/rng/rdrand_rng/rdrand_rng.h3
-rw-r--r--src/lib/rng/rng.cpp140
-rw-r--r--src/lib/rng/rng.h137
-rw-r--r--src/lib/rng/stateful_rng/info.txt2
-rw-r--r--src/lib/rng/stateful_rng/stateful_rng.cpp112
-rw-r--r--src/lib/rng/stateful_rng/stateful_rng.h118
-rw-r--r--src/lib/rng/x931_rng/info.txt4
-rw-r--r--src/lib/rng/x931_rng/x931_rng.cpp10
-rw-r--r--src/lib/rng/x931_rng/x931_rng.h9
-rw-r--r--src/lib/utils/os_utils.cpp6
-rw-r--r--src/lib/utils/os_utils.h2
26 files changed, 758 insertions, 356 deletions
diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h
index 64d988e7c..94c67a18e 100644
--- a/src/lib/entropy/entropy_src.h
+++ b/src/lib/entropy/entropy_src.h
@@ -8,12 +8,17 @@
#ifndef BOTAN_ENTROPY_H__
#define BOTAN_ENTROPY_H__
+#include <botan/secmem.h>
#include <botan/rng.h>
#include <string>
#include <chrono>
+#include <memory>
+#include <vector>
namespace Botan {
+class RandomNumberGenerator;
+
/**
* Abstract interface to a source of entropy
*/
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index 028b286b6..e42f32234 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -287,7 +287,7 @@ int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len)
int botan_rng_reseed(botan_rng_t rng, size_t bits)
{
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed(bits); });
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); });
}
int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
diff --git a/src/lib/prov/pkcs11/p11_randomgenerator.h b/src/lib/prov/pkcs11/p11_randomgenerator.h
index 84673278d..a291c89f3 100644
--- a/src/lib/prov/pkcs11/p11_randomgenerator.h
+++ b/src/lib/prov/pkcs11/p11_randomgenerator.h
@@ -22,7 +22,7 @@ namespace PKCS11 {
class Module;
/// A random generator that only fetches random from the PKCS#11 RNG
-class BOTAN_DLL PKCS11_RNG final : public RandomNumberGenerator
+class BOTAN_DLL PKCS11_RNG final : public Hardware_RNG
{
public:
/// Initialize the RNG with the PKCS#11 session that provides access to the cryptoki functions
@@ -43,7 +43,7 @@ class BOTAN_DLL PKCS11_RNG final : public RandomNumberGenerator
}
/// No operation - always returns 0
- size_t reseed_with_sources(Entropy_Sources&, size_t, std::chrono::milliseconds) override
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override
{
return 0;
}
diff --git a/src/lib/pubkey/rfc6979/rfc6979.cpp b/src/lib/pubkey/rfc6979/rfc6979.cpp
index 1173eefee..94b313c3a 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.cpp
+++ b/src/lib/pubkey/rfc6979/rfc6979.cpp
@@ -17,10 +17,10 @@ RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash,
m_order(order),
m_qlen(m_order.bits()),
m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)),
- m_hmac_drbg(new HMAC_DRBG(hash, 0)),
m_rng_in(m_rlen * 2),
m_rng_out(m_rlen)
{
+ m_hmac_drbg.reset(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")")));
BigInt::encode_1363(m_rng_in.data(), m_rlen, x);
}
diff --git a/src/lib/rng/auto_rng.h b/src/lib/rng/auto_rng.h
deleted file mode 100644
index 3085623ef..000000000
--- a/src/lib/rng/auto_rng.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-* Auto Seeded RNG
-* (C) 2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_AUTO_SEEDING_RNG_H__
-#define BOTAN_AUTO_SEEDING_RNG_H__
-
-#include <botan/rng.h>
-
-namespace Botan {
-
-class BOTAN_DLL AutoSeeded_RNG final : public RandomNumberGenerator
- {
- public:
- void randomize(byte out[], size_t len) override;
-
- void randomize_with_input(byte output[], size_t output_len,
- const byte input[], size_t input_len) override;
-
- bool is_seeded() const override { return m_rng->is_seeded(); }
-
- void clear() override { m_rng->clear(); m_counter = 0; }
-
- std::string name() const override { return m_rng->name(); }
-
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override
- {
- return m_rng->reseed_with_sources(srcs, poll_bits, poll_timeout);
- }
-
- void add_entropy(const byte in[], size_t len) override
- { m_rng->add_entropy(in, len); }
-
- AutoSeeded_RNG(size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
- private:
- std::unique_ptr<RandomNumberGenerator> m_rng;
- uint32_t m_counter = 0;
- };
-
-}
-
-#endif
diff --git a/src/lib/rng/auto_rng/auto_rng.cpp b/src/lib/rng/auto_rng/auto_rng.cpp
new file mode 100644
index 000000000..a9da085bc
--- /dev/null
+++ b/src/lib/rng/auto_rng/auto_rng.cpp
@@ -0,0 +1,116 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/auto_rng.h>
+#include <botan/entropy_src.h>
+
+#if defined(BOTAN_HAS_HMAC_DRBG)
+ #include <botan/hmac_drbg.h>
+#endif
+
+#if defined(BOTAN_HAS_HMAC_RNG)
+ #include <botan/hmac_rng.h>
+#endif
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#endif
+
+namespace Botan {
+
+AutoSeeded_RNG::~AutoSeeded_RNG()
+ {
+ // for unique_ptr
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ underlying_rng,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ entropy_sources,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ underlying_rng,
+ entropy_sources,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(size_t reseed_interval) :
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ AutoSeeded_RNG(system_rng(), reseed_interval)
+#else
+ AutoSeeded_RNG(Entropy_Sources::global_sources(), reseed_interval)
+#endif
+ {
+ }
+
+void AutoSeeded_RNG::force_reseed()
+ {
+ m_rng->force_reseed();
+ m_rng->next_byte();
+
+ if(!m_rng->is_seeded())
+ {
+ throw Exception("AutoSeeded_RNG reseeding failed");
+ }
+ }
+
+bool AutoSeeded_RNG::is_seeded() const
+ {
+ return m_rng->is_seeded();
+ }
+
+void AutoSeeded_RNG::clear()
+ {
+ m_rng->clear();
+ }
+
+std::string AutoSeeded_RNG::name() const
+ {
+ return m_rng->name();
+ }
+
+void AutoSeeded_RNG::add_entropy(const byte in[], size_t len)
+ {
+ m_rng->add_entropy(in, len);
+ }
+
+size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ return m_rng->reseed(srcs, poll_bits, poll_timeout);
+ }
+
+void AutoSeeded_RNG::randomize(byte output[], size_t output_len)
+ {
+ randomize_with_ts_input(output, output_len);
+ }
+
+void AutoSeeded_RNG::randomize_with_input(byte output[], size_t output_len,
+ const byte ad[], size_t ad_len)
+ {
+ m_rng->randomize_with_input(output, output_len, ad, ad_len);
+ }
+
+}
diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng/auto_rng.h
new file mode 100644
index 000000000..6ef1aa291
--- /dev/null
+++ b/src/lib/rng/auto_rng/auto_rng.h
@@ -0,0 +1,67 @@
+/*
+* Auto Seeded RNG
+* (C) 2008,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_AUTO_SEEDING_RNG_H__
+#define BOTAN_AUTO_SEEDING_RNG_H__
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+class Stateful_RNG;
+
+/**
+* A userspace PRNG
+*/
+class BOTAN_DLL AutoSeeded_RNG final : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte out[], size_t len) override;
+
+ void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len) override;
+
+ bool is_seeded() const override;
+
+ void force_reseed();
+
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override;
+
+ void add_entropy(const byte in[], size_t len) override;
+
+ std::string name() const override;
+
+ void clear() override;
+
+ /**
+ * If no RNG or entropy sources are provided to AutoSeeded_RNG, it uses the system RNG
+ * (if available) or else a default group of entropy sources (all other systems) to
+ * gather seed material.
+ */
+ AutoSeeded_RNG(size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ AutoSeeded_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ ~AutoSeeded_RNG();
+
+ private:
+ std::unique_ptr<Stateful_RNG> m_rng;
+ };
+
+}
+
+#endif
diff --git a/src/lib/rng/auto_rng/info.txt b/src/lib/rng/auto_rng/info.txt
new file mode 100644
index 000000000..b77e6aa54
--- /dev/null
+++ b/src/lib/rng/auto_rng/info.txt
@@ -0,0 +1 @@
+define AUTO_SEEDING_RNG 20160821
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
index 7325804e3..6ea66aa2e 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
@@ -10,28 +10,42 @@
namespace Botan {
-HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* hmac,
- size_t max_output_before_reseed) :
- Stateful_RNG(max_output_before_reseed),
- m_mac(hmac)
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_mac(std::move(prf))
{
- m_V.resize(m_mac->output_length());
+ BOTAN_ASSERT_NONNULL(m_mac);
clear();
}
-HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash,
- size_t max_output_before_reseed) :
- Stateful_RNG(max_output_before_reseed)
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
+ m_mac(std::move(prf))
{
- const std::string hmac = "HMAC(" + hmac_hash + ")";
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
- m_mac = MessageAuthenticationCode::create(hmac);
- if(!m_mac)
- {
- throw Algorithm_Not_Found(hmac);
- }
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_mac(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
- m_V.resize(m_mac->output_length());
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_mac(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
clear();
}
@@ -39,6 +53,7 @@ void HMAC_DRBG::clear()
{
Stateful_RNG::clear();
+ m_V.resize(m_mac->output_length());
for(size_t i = 0; i != m_V.size(); ++i)
m_V[i] = 0x01;
m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
@@ -61,25 +76,45 @@ void HMAC_DRBG::randomize(byte output[], size_t output_len)
void HMAC_DRBG::randomize_with_input(byte output[], size_t output_len,
const byte input[], size_t input_len)
{
- reseed_check(output_len);
-
- if(input_len > 0)
+ /**
+ * SP 800-90A requires we reject any request for a DRBG output
+ * longer than max_number_of_bits_per_request. This is an
+ * implementation-dependent value, but NIST requires for HMAC_DRBG
+ * that every implementation set a value no more than 2**19 bits
+ * (or 64 KiB).
+ *
+ * To avoid inconveniencing the caller who wants a large output for
+ * whatever reason, instead treat very long output requests as
+ * if multiple maximum-length requests had been made.
+ */
+ const size_t max_number_of_bytes_per_request = 64*1024;
+
+ while(output_len > 0)
{
- update(input, input_len);
- }
+ size_t this_req = std::min(max_number_of_bytes_per_request, output_len);
+ output_len -= this_req;
- while(output_len)
- {
- const size_t to_copy = std::min(output_len, m_V.size());
- m_mac->update(m_V.data(), m_V.size());
- m_mac->final(m_V.data());
- copy_mem(output, m_V.data(), to_copy);
+ reseed_check();
+
+ if(input_len > 0)
+ {
+ update(input, input_len);
+ }
+
+ while(this_req)
+ {
+ const size_t to_copy = std::min(this_req, m_V.size());
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
+ copy_mem(output, m_V.data(), to_copy);
- output += to_copy;
- output_len -= to_copy;
+ output += to_copy;
+ this_req -= to_copy;
+ }
+
+ update(input, input_len);
}
- update(input, input_len);
}
/*
@@ -113,4 +148,10 @@ void HMAC_DRBG::add_entropy(const byte input[], size_t input_len)
update(input, input_len);
}
+size_t HMAC_DRBG::security_level() const
+ {
+ // sqrt of hash size
+ return m_mac->output_length() * 8 / 2;
+ }
+
}
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h
index 0e294dbdb..4f96af816 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.h
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.h
@@ -8,11 +8,13 @@
#ifndef BOTAN_HMAC_DRBG_H__
#define BOTAN_HMAC_DRBG_H__
-#include <botan/rng.h>
+#include <botan/stateful_rng.h>
#include <botan/mac.h>
namespace Botan {
+class Entropy_Sources;
+
/**
* HMAC_DRBG from NIST SP800-90A
*/
@@ -20,13 +22,64 @@ class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG
{
public:
/**
- * Initialize an HMAC_DRBG instance with the given hash function
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding is disabled completely, as it as no access to
+ * any source for seed material.
+ *
+ * If a fork is detected, the RNG will be unable to reseed itself
+ * in response. In this case, an exception will be thrown rather
+ * than generating duplicated output.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf);
+
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
*/
- HMAC_DRBG(const std::string& hmac_hash,
- size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- HMAC_DRBG(MessageAuthenticationCode* hmac,
- size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Constructor taking a string for the hash
+ */
+ HMAC_DRBG(const std::string& hmac_hash) : Stateful_RNG()
+ {
+ m_mac = MessageAuthenticationCode::create("HMAC(" + hmac_hash + ")");
+ if(!m_mac)
+ throw Algorithm_Not_Found(hmac_hash);
+ clear();
+ }
std::string name() const override;
@@ -38,6 +91,9 @@ class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG
const byte input[], size_t input_len) override;
void add_entropy(const byte input[], size_t input_len) override;
+
+ size_t security_level() const override;
+
private:
void update(const byte input[], size_t input_len);
diff --git a/src/lib/rng/hmac_drbg/info.txt b/src/lib/rng/hmac_drbg/info.txt
index f386db199..7f2c12fd0 100644
--- a/src/lib/rng/hmac_drbg/info.txt
+++ b/src/lib/rng/hmac_drbg/info.txt
@@ -2,4 +2,5 @@ define HMAC_DRBG 20140319
<requires>
hmac
+stateful_rng
</requires>
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index c100cf70f..d66c538ab 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -12,43 +12,71 @@
namespace Botan {
-HMAC_RNG::HMAC_RNG(const std::string& hash, size_t max_output_before_reseed) :
- Stateful_RNG(max_output_before_reseed)
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_prf(std::move(prf))
{
- m_extractor = MAC::create("HMAC(" + hash + ")");
- if(!m_extractor)
- throw Invalid_Argument("HMAC_RNG hash not found");
+ BOTAN_ASSERT_NONNULL(m_prf);
- m_prf.reset(m_extractor->clone());
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
- if(!m_prf->valid_keylength(m_extractor->output_length()) ||
- !m_extractor->valid_keylength(m_prf->output_length()))
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
{
- throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
- m_extractor->name() + " and " +
- m_prf->name());
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
}
+ m_extractor.reset(m_prf->clone());
this->clear();
}
-/*
-* HMAC_RNG Constructor
-*/
-HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf,
- size_t max_output_before_reseed) :
- Stateful_RNG(max_output_before_reseed),
- m_extractor(extractor), m_prf(prf)
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_prf(std::move(prf)),
+ m_extractor(m_prf->clone())
{
- if(!m_prf->valid_keylength(m_extractor->output_length()) ||
- !m_extractor->valid_keylength(m_prf->output_length()))
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
{
- throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
- m_extractor->name() + " and " +
- m_prf->name());
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
}
+ m_extractor.reset(m_prf->clone());
this->clear();
}
@@ -105,7 +133,7 @@ void HMAC_RNG::new_K_value(byte label)
*/
void HMAC_RNG::randomize(byte out[], size_t length)
{
- reseed_check(length);
+ reseed_check();
while(length)
{
@@ -121,9 +149,9 @@ void HMAC_RNG::randomize(byte out[], size_t length)
new_K_value(BlockFinished);
}
-size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds timeout)
+size_t HMAC_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
new_K_value(Reseed);
m_extractor->update(m_K); // m_K is the PRF output
@@ -131,7 +159,7 @@ size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
/*
* This ends up calling add_entropy which provides input to the extractor
*/
- size_t bits_collected = Stateful_RNG::reseed_with_sources(srcs, poll_bits, timeout);
+ size_t bits_collected = Stateful_RNG::reseed(srcs, poll_bits, timeout);
/*
Now derive the new PRK using everything that has been fed into
diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h
index a2538a83a..d6e9b4896 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.h
+++ b/src/lib/rng/hmac_rng/hmac_rng.h
@@ -1,6 +1,6 @@
/*
* HMAC RNG
-* (C) 2008,2013 Jack Lloyd
+* (C) 2008,2013,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,9 +8,8 @@
#ifndef BOTAN_HMAC_RNG_H__
#define BOTAN_HMAC_RNG_H__
+#include <botan/stateful_rng.h>
#include <botan/mac.h>
-#include <botan/rng.h>
-#include <vector>
namespace Botan {
@@ -19,40 +18,69 @@ namespace Botan {
* Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk
* (henceforce, 'E-t-E')
*
-* However it actually can be parameterized with any two MAC functions,
+* However it actually could be parameterized with any two MAC functions,
* not restricted to HMAC (this variation is also described in
* Krawczyk's paper), for instance one could use HMAC(SHA-512) as the
* extractor and CMAC(AES-256) as the PRF.
*/
-class BOTAN_DLL HMAC_RNG : public Stateful_RNG
+class BOTAN_DLL HMAC_RNG final : public Stateful_RNG
{
public:
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding.
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding.
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /*
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * Automatic reseeding is disabled completely.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf);
+
void randomize(byte buf[], size_t len) override;
void clear() override;
std::string name() const override;
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte[], size_t) override;
- /**
- * @param extractor a MAC used for extracting the entropy
- * @param prf a MAC used as a PRF using HKDF construction
- */
- HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf,
- size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
+ size_t security_level() const override { return m_prf->output_length() * 8 / 2; }
- /**
- * Use the specified hash for both the extractor and PRF functions
- */
- HMAC_RNG(const std::string& hash,
- size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
private:
- std::unique_ptr<MessageAuthenticationCode> m_extractor;
std::unique_ptr<MessageAuthenticationCode> m_prf;
+ std::unique_ptr<MessageAuthenticationCode> m_extractor;
enum HMAC_PRF_Label {
Running,
diff --git a/src/lib/rng/hmac_rng/info.txt b/src/lib/rng/hmac_rng/info.txt
index 36a8a7a34..2b7f49c8a 100644
--- a/src/lib/rng/hmac_rng/info.txt
+++ b/src/lib/rng/hmac_rng/info.txt
@@ -2,4 +2,5 @@ define HMAC_RNG 20131128
<requires>
mac
+stateful_rng
</requires>
diff --git a/src/lib/rng/info.txt b/src/lib/rng/info.txt
index 84ba3ce89..655e35fd1 100644
--- a/src/lib/rng/info.txt
+++ b/src/lib/rng/info.txt
@@ -1,5 +1,3 @@
-define AUTO_SEEDING_RNG 20131128
-
<requires>
entropy
hmac_drbg
diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/lib/rng/rdrand_rng/rdrand_rng.h
index d0fb37c16..fcd54035b 100644
--- a/src/lib/rng/rdrand_rng/rdrand_rng.h
+++ b/src/lib/rng/rdrand_rng/rdrand_rng.h
@@ -45,8 +45,7 @@ class BOTAN_DLL RDRAND_RNG : public Hardware_RNG
void add_entropy(const uint8_t[], size_t) override
{ /* no op */ }
- size_t reseed_with_sources(Entropy_Sources&, size_t,
- std::chrono::milliseconds) override
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override
{ return 0; /* no op */ }
std::string name() const override { return "RDRAND"; }
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp
index 5501c143e..8c2982312 100644
--- a/src/lib/rng/rng.cpp
+++ b/src/lib/rng/rng.cpp
@@ -1,144 +1,62 @@
/*
-* Random Number Generator
-* (C) 1999-2008,2016 Jack Lloyd
+* (C) 2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/rng.h>
-#include <botan/auto_rng.h>
-#include <botan/entropy_src.h>
#include <botan/loadstor.h>
#include <botan/internal/os_utils.h>
-#if defined(BOTAN_HAS_HMAC_DRBG)
- #include <botan/hmac_drbg.h>
-#endif
-
-#if defined(BOTAN_HAS_HMAC_RNG)
- #include <botan/hmac_rng.h>
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+ #include <botan/auto_rng.h>
#endif
namespace Botan {
-size_t RandomNumberGenerator::reseed(size_t bits_to_collect)
+void RandomNumberGenerator::randomize_with_ts_input(byte output[], size_t output_len)
{
- return this->reseed_with_timeout(bits_to_collect,
- BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
- }
-
-size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect,
- std::chrono::milliseconds timeout)
- {
- return this->reseed_with_sources(Entropy_Sources::global_sources(),
- bits_to_collect,
- timeout);
- }
-
-size_t RandomNumberGenerator::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
- {
- return srcs.poll(*this, poll_bits, poll_timeout);
- }
-
-Stateful_RNG::Stateful_RNG(size_t max_output_before_reseed) : m_max_output_before_reseed(max_output_before_reseed)
- {
- }
-
-void Stateful_RNG::clear()
- {
- m_successful_initialization = false;
- m_bytes_since_reseed = 0;
- m_last_pid = 0;
- }
-
-size_t Stateful_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
- {
- size_t bits_collected = RandomNumberGenerator::reseed_with_sources(srcs, poll_bits, poll_timeout);
-
- if(bits_collected >= poll_bits)
- {
- m_successful_initialization = true;
- m_bytes_since_reseed = 0;
- }
+ /*
+ Form additional input which is provided to the PRNG implementation
+ to paramaterize the KDF output.
+ */
+ byte additional_input[16] = { 0 };
+ store_le(OS::get_system_timestamp_ns(), additional_input);
+ store_le(OS::get_processor_timestamp(), additional_input + 8);
- return bits_collected;
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
}
-void Stateful_RNG::reseed_check(size_t bytes_requested)
+void RandomNumberGenerator::randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len)
{
- const bool fork_detected = (m_last_pid > 0) && (OS::get_process_id() != m_last_pid);
-
- m_bytes_since_reseed += bytes_requested;
- m_last_pid = OS::get_process_id();
-
- if(!is_seeded() || fork_detected)
- {
- this->reseed(BOTAN_RNG_RESEED_POLL_BITS);
- }
- else if(m_max_output_before_reseed > 0 && m_bytes_since_reseed >= m_max_output_before_reseed)
- {
- this->reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS,
- BOTAN_RNG_AUTO_RESEED_TIMEOUT);
- }
-
- if(!is_seeded())
- {
- throw PRNG_Unseeded(name());
- }
+ this->add_entropy(input, input_len);
+ this->randomize(output, output_len);
}
-void Stateful_RNG::initialize_with(const byte input[], size_t len)
+size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
- add_entropy(input, len);
- m_successful_initialization = true;
+ return srcs.poll(*this, poll_bits, poll_timeout);
}
-bool Stateful_RNG::is_seeded() const
+void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
{
- return m_successful_initialization;
+ secure_vector<byte> buf(poll_bits / 8);
+ rng.randomize(buf.data(), buf.size());
+ this->add_entropy(buf.data(), buf.size());
}
RandomNumberGenerator* RandomNumberGenerator::make_rng()
{
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
return new AutoSeeded_RNG;
+#else
+ throw Exception("make_rng failed, no AutoSeeded_RNG in this build");
+#endif
}
-AutoSeeded_RNG::AutoSeeded_RNG(size_t max_output_before_reseed)
- {
- m_rng.reset(new BOTAN_AUTO_RNG_DRBG(BOTAN_AUTO_RNG_HASH, max_output_before_reseed));
-
- size_t bits = m_rng->reseed(BOTAN_AUTO_RNG_ENTROPY_TARGET);
-
- if(!m_rng->is_seeded())
- {
- throw Exception("AutoSeeded_RNG failed to gather enough entropy only got " +
- std::to_string(bits) + " bits");
- }
- }
-
-void AutoSeeded_RNG::randomize(byte output[], size_t output_len)
- {
- /*
- Form additional input which is provided to the PRNG implementation
- to paramaterize the KDF output.
- */
- byte additional_input[24] = { 0 };
- store_le(OS::get_system_timestamp_ns(), additional_input);
- store_le(OS::get_processor_timestamp(), additional_input + 8);
- store_le(OS::get_process_id(), additional_input + 16);
- store_le(m_counter++, additional_input + 20);
-
- randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
- }
-
-void AutoSeeded_RNG::randomize_with_input(byte output[], size_t output_len,
- const byte ad[], size_t ad_len)
- {
- m_rng->randomize_with_input(output, output_len, ad, ad_len);
- }
+Serialized_RNG::Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
}
diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h
index 7da560b85..d1cdcfff2 100644
--- a/src/lib/rng/rng.h
+++ b/src/lib/rng/rng.h
@@ -8,6 +8,7 @@
#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__
#define BOTAN_RANDOM_NUMBER_GENERATOR_H__
+#include <botan/entropy_src.h>
#include <botan/secmem.h>
#include <botan/exceptn.h>
#include <chrono>
@@ -19,7 +20,7 @@ namespace Botan {
class Entropy_Sources;
/**
-* An interface to a generic RNG
+* An interface to a cryptographic random number generator
*/
class BOTAN_DLL RandomNumberGenerator
{
@@ -45,6 +46,8 @@ class BOTAN_DLL RandomNumberGenerator
* Incorporate some additional data into the RNG state. For
* example adding nonces or timestamps from a peer's protocol
* message can help hedge against VM state rollback attacks.
+ * A few RNG types do not accept any externally provided input,
+ * in which case this function is a no-op.
*
* @param inputs a byte array containg the entropy to be added
* @param length the length of the byte array in
@@ -56,27 +59,41 @@ class BOTAN_DLL RandomNumberGenerator
*/
template<typename T> void add_entropy_T(const T& t)
{
- add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
+ this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
}
/**
- * Incorporate entropy into the RNG state then produce output
- * Some RNG types implement this using a single operation.
+ * Incorporate entropy into the RNG state then produce output.
+ * Some RNG types implement this using a single operation, default
+ * calls add_entropy + randomize in sequence.
+ *
+ * Use this to further bind the outputs to your current
+ * process/protocol state. For instance if generating a new key
+ * for use in a session, include a session ID or other such
+ * value. See NIST SP 800-90 A, B, C series for more ideas.
*/
virtual void randomize_with_input(byte output[], size_t output_len,
- const byte input[], size_t input_len)
- {
- this->add_entropy(input, input_len);
- this->randomize(output, output_len);
- }
+ const byte input[], size_t input_len);
+
+ /**
+ * This calls `randomize_with_input` using some timestamps as extra input.
+ *
+ * For a stateful RNG using non-random but potentially unique data as the
+ * additional_input can help protect against problems with fork, VM state
+ * rollback, or other cases where somehow an RNG state is duplicated. If
+ * both of the duplicated RNG states later incorporate a timestamp (and the
+ * timestamps don't themselves repeat), their outputs will diverge.
+ */
+ virtual void randomize_with_ts_input(byte output[], size_t output_len);
/**
- * Return the name of this object
+ * Return the name of this RNG type
*/
virtual std::string name() const = 0;
/**
- * Clear all internally held values of this RNG.
+ * Clear all internally held values of this RNG
+ * @post is_seeded() == false
*/
virtual void clear() = 0;
@@ -91,28 +108,17 @@ class BOTAN_DLL RandomNumberGenerator
* or until the timeout expires. Returns estimate of the number
* of bits collected.
*/
- virtual size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout);
+ virtual size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
/**
- * Reseed this RNG from the default entropy sources and a default timeout
- * @param bits_to_collect is the number of bits of entropy to
- * attempt to gather from the entropy sources
- * @param poll_timeout try not to run longer than this, even if
- * not enough entropy has been collected
+ * Reseed by reading specified bits from the RNG
*/
- size_t reseed(size_t bits_to_collect = BOTAN_RNG_RESEED_POLL_BITS);
+ virtual void reseed_from_rng(RandomNumberGenerator& rng,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS);
- /**
- * Reseed this RNG from the default entropy sources
- * @param bits_to_collect is the number of bits of entropy to
- * attempt to gather from the entropy sources
- * @param poll_timeout try not to run longer than this, even if
- * not enough entropy has been collected
- */
- size_t reseed_with_timeout(size_t bits_to_collect,
- std::chrono::milliseconds poll_timeout);
+ // Some utility functions built on the interface above:
/**
* Return a random vector
@@ -122,7 +128,7 @@ class BOTAN_DLL RandomNumberGenerator
secure_vector<byte> random_vec(size_t bytes)
{
secure_vector<byte> output(bytes);
- randomize(output.data(), output.size());
+ this->randomize(output.data(), output.size());
return output;
}
@@ -139,9 +145,9 @@ class BOTAN_DLL RandomNumberGenerator
byte next_nonzero_byte()
{
- byte b = next_byte();
+ byte b = this->next_byte();
while(b == 0)
- b = next_byte();
+ b = this->next_byte();
return b;
}
@@ -150,65 +156,11 @@ class BOTAN_DLL RandomNumberGenerator
* Added in 1.8.0
* Use AutoSeeded_RNG instead
*/
+ BOTAN_DEPRECATED("Use AutoSeeded_RNG")
static RandomNumberGenerator* make_rng();
};
/**
-* Inherited by RNGs which maintain in-process state, like HMAC_DRBG.
-* On Unix these RNGs are vulnerable to problems with fork, where the
-* RNG state is duplicated, and the parent and child process RNGs will
-* produce identical output until one of them reseeds. Stateful_RNG
-* reseeds itself whenever a fork is detected, or after a set number of
-* bytes have been output.
-*
-* Not implemented by RNGs which access an external RNG, such as the
-* system PRNG or a hardware RNG.
-*/
-class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator
- {
- public:
- Stateful_RNG(size_t max_output_before_reseed);
-
- virtual bool is_seeded() const override final;
-
- /**
- * Consume this input and mark the RNG as initialized regardless
- * of the length of the input or the current seeded state of
- * the RNG.
- */
- void initialize_with(const byte input[], size_t length);
-
- /**
- * Poll provided sources for up to poll_bits bits of entropy
- * or until the timeout expires. Returns estimate of the number
- * of bits collected.
- */
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
-
- protected:
- void reseed_check(size_t bytes_requested);
-
- void clear() override;
-
- /**
- * Mark state as requiring a reseed on next use
- */
- void force_reseed() { m_bytes_since_reseed = m_max_output_before_reseed; }
-
- uint32_t last_pid() const { return m_last_pid; }
-
- mutable std::mutex m_mutex;
-
- private:
- const size_t m_max_output_before_reseed;
- size_t m_bytes_since_reseed = 0;
- uint32_t m_last_pid = 0;
- bool m_successful_initialization = false;
- };
-
-/**
* Convenience typedef
*/
typedef RandomNumberGenerator RNG;
@@ -271,12 +223,12 @@ class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator
return m_rng->name();
}
- size_t reseed_with_sources(Entropy_Sources& src,
- size_t bits,
- std::chrono::milliseconds msec) override
+ size_t reseed(Entropy_Sources& src,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override
{
std::lock_guard<std::mutex> lock(m_mutex);
- return m_rng->reseed_with_sources(src, bits, msec);
+ return m_rng->reseed(src, poll_bits, poll_timeout);
}
void add_entropy(const byte in[], size_t len) override
@@ -285,7 +237,8 @@ class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator
m_rng->add_entropy(in, len);
}
- Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
+ BOTAN_DEPRECATED("Create an AutoSeeded_RNG for other constructor") Serialized_RNG();
+
explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {}
private:
mutable std::mutex m_mutex;
diff --git a/src/lib/rng/stateful_rng/info.txt b/src/lib/rng/stateful_rng/info.txt
new file mode 100644
index 000000000..b4dcedf4a
--- /dev/null
+++ b/src/lib/rng/stateful_rng/info.txt
@@ -0,0 +1,2 @@
+define STATEFUL_RNG 20160819
+
diff --git a/src/lib/rng/stateful_rng/stateful_rng.cpp b/src/lib/rng/stateful_rng/stateful_rng.cpp
new file mode 100644
index 000000000..1349c1208
--- /dev/null
+++ b/src/lib/rng/stateful_rng/stateful_rng.cpp
@@ -0,0 +1,112 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/stateful_rng.h>
+#include <botan/internal/os_utils.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+void Stateful_RNG::clear()
+ {
+ m_reseed_counter = 0;
+ m_last_pid = 0;
+ }
+
+void Stateful_RNG::force_reseed()
+ {
+ m_reseed_counter = 0;
+ }
+
+bool Stateful_RNG::is_seeded() const
+ {
+ return m_reseed_counter > 0;
+ }
+
+void Stateful_RNG::initialize_with(const byte input[], size_t len)
+ {
+ add_entropy(input, len);
+
+ if(8*len >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+ }
+
+void Stateful_RNG::randomize_with_ts_input(byte output[], size_t output_len)
+ {
+ byte additional_input[24] = { 0 };
+ store_le(OS::get_system_timestamp_ns(), additional_input);
+ store_le(OS::get_processor_timestamp(), additional_input + 8);
+ store_le(m_last_pid, additional_input + 16);
+ store_le(static_cast<uint32_t>(m_reseed_counter), additional_input + 20);
+
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
+ }
+
+size_t Stateful_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout);
+
+ if(bits_collected >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+
+ return bits_collected;
+ }
+
+void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
+ {
+ RandomNumberGenerator::reseed_from_rng(rng, poll_bits);
+
+ if(poll_bits >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+ }
+
+void Stateful_RNG::reseed_check()
+ {
+ const uint32_t cur_pid = OS::get_process_id();
+
+ const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid);
+
+ if(is_seeded() == false ||
+ fork_detected ||
+ (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval))
+ {
+ m_reseed_counter = 0;
+ m_last_pid = cur_pid;
+
+ if(m_underlying_rng)
+ {
+ reseed_from_rng(*m_underlying_rng, security_level());
+ }
+
+ if(m_entropy_sources)
+ {
+ reseed(*m_entropy_sources, security_level());
+ }
+
+ if(!is_seeded())
+ {
+ if(fork_detected)
+ throw Exception("Detected use of fork but cannot reseed DRBG");
+ else
+ throw PRNG_Unseeded(name());
+ }
+ }
+ else
+ {
+ BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded");
+ m_reseed_counter += 1;
+ }
+ }
+
+}
diff --git a/src/lib/rng/stateful_rng/stateful_rng.h b/src/lib/rng/stateful_rng/stateful_rng.h
new file mode 100644
index 000000000..11f0c7e3d
--- /dev/null
+++ b/src/lib/rng/stateful_rng/stateful_rng.h
@@ -0,0 +1,118 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_STATEFUL_RNG_H__
+#define BOTAN_STATEFUL_RNG_H__
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+/**
+* Inherited by RNGs which maintain in-process state, like HMAC_DRBG.
+* On Unix these RNGs are vulnerable to problems with fork, where the
+* RNG state is duplicated, and the parent and child process RNGs will
+* produce identical output until one of them reseeds. Stateful_RNG
+* reseeds itself whenever a fork is detected, or after a set number of
+* bytes have been output.
+*
+* Not implemented by RNGs which access an external RNG, such as the
+* system PRNG or a hardware RNG.
+*/
+class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator
+ {
+ public:
+ Stateful_RNG(RandomNumberGenerator& rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ m_underlying_rng(&rng),
+ m_entropy_sources(&entropy_sources),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ Stateful_RNG(RandomNumberGenerator& rng, size_t reseed_interval) :
+ m_underlying_rng(&rng),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ Stateful_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) :
+ m_entropy_sources(&entropy_sources),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ /**
+ * In this case, automatic reseeding is impossible
+ */
+ Stateful_RNG() : m_reseed_interval(0) {}
+
+ /**
+ * Consume this input and mark the RNG as initialized regardless
+ * of the length of the input or the current seeded state of
+ * the RNG.
+ */
+ void initialize_with(const byte input[], size_t length);
+
+ bool is_seeded() const override final;
+
+ /**
+ * Mark state as requiring a reseed on next use
+ */
+ void force_reseed();
+
+ void reseed_from_rng(RandomNumberGenerator& rng,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) override final;
+
+ /**
+ * Overrides default implementation and also includes the current
+ * process ID and the reseed counter.
+ */
+ void randomize_with_ts_input(byte output[], size_t output_len) override final;
+
+ /**
+ * Poll provided sources for up to poll_bits bits of entropy
+ * or until the timeout expires. Returns estimate of the number
+ * of bits collected.
+ */
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override;
+
+ /**
+ * Return intended security level of this DRBG
+ */
+ virtual size_t security_level() const = 0;
+
+ void clear() override;
+
+ protected:
+ /**
+ * Called with lock held
+ */
+ void reseed_check();
+
+ uint32_t last_pid() const { return m_last_pid; }
+
+ private:
+ // A non-owned and possibly null pointer to shared RNG
+ RandomNumberGenerator* m_underlying_rng = nullptr;
+
+ // A non-owned and possibly null pointer to a shared Entropy_Source
+ Entropy_Sources* m_entropy_sources = nullptr;
+
+ const size_t m_reseed_interval;
+
+ /*
+ * Set to 1 after a sucessful seeding, then incremented. Reset
+ * to 0 by clear() or a fork. This logic is used even if
+ * automatic reseeding is disabled (via m_reseed_interval = 0)
+ */
+ size_t m_reseed_counter = 0;
+ uint32_t m_last_pid = 0;
+ };
+
+}
+
+#endif
diff --git a/src/lib/rng/x931_rng/info.txt b/src/lib/rng/x931_rng/info.txt
index b61dc7ec9..4a4418083 100644
--- a/src/lib/rng/x931_rng/info.txt
+++ b/src/lib/rng/x931_rng/info.txt
@@ -1 +1,5 @@
define X931_RNG 20131128
+
+<requires>
+stateful_rng
+</requires>
diff --git a/src/lib/rng/x931_rng/x931_rng.cpp b/src/lib/rng/x931_rng/x931_rng.cpp
index 020d9a5a5..ed44dc743 100644
--- a/src/lib/rng/x931_rng/x931_rng.cpp
+++ b/src/lib/rng/x931_rng/x931_rng.cpp
@@ -14,7 +14,7 @@ void ANSI_X931_RNG::randomize(byte out[], size_t length)
{
if(!is_seeded())
{
- reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ rekey();
if(!is_seeded())
throw PRNG_Unseeded(name());
@@ -72,11 +72,11 @@ void ANSI_X931_RNG::rekey()
}
}
-size_t ANSI_X931_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
+size_t ANSI_X931_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
- size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
+ size_t bits = m_prng->reseed(srcs, poll_bits, poll_timeout);
rekey();
return bits;
}
diff --git a/src/lib/rng/x931_rng/x931_rng.h b/src/lib/rng/x931_rng/x931_rng.h
index ed7124a08..861fcffde 100644
--- a/src/lib/rng/x931_rng/x931_rng.h
+++ b/src/lib/rng/x931_rng/x931_rng.h
@@ -16,7 +16,7 @@ namespace Botan {
/**
* ANSI X9.31 RNG
*/
-class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
+class BOTAN_DLL ANSI_X931_RNG final : public RandomNumberGenerator
{
public:
void randomize(byte[], size_t) override;
@@ -24,9 +24,9 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
void clear() override;
std::string name() const override;
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte[], size_t) override;
@@ -35,6 +35,7 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
* @param rng the underlying PRNG for generating inputs
* (eg, an HMAC_RNG)
*/
+ BOTAN_DEPRECATED("X9.31 RNG is deprecated and will be removed soon")
ANSI_X931_RNG(BlockCipher* cipher,
RandomNumberGenerator* rng);
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index 86776bdd0..c00c898a3 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -19,7 +19,7 @@
#include <unistd.h>
#endif
-#if defined(BOTAN_TARGET_OS_TYPE_IS_WINDOWS)
+#if defined(BOTAN_TARGET_OS_IS_WINDOWS)
#include <windows.h>
#endif
@@ -29,12 +29,12 @@ namespace OS {
uint32_t get_process_id()
{
-#if defined(BOTAN_TARGET_OS_IS_UNIX)
+#if defined(BOTAN_TARGET_OS_TYPE_IS_UNIX)
return ::getpid();
#elif defined(BOTAN_TARGET_OS_IS_WINDOWS)
return ::GetCurrentProcessId();
#else
- return 0;
+ throw Exception("get_process_id not supported");
#endif
}
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
index 3335463f7..590ed4ae7 100644
--- a/src/lib/utils/os_utils.h
+++ b/src/lib/utils/os_utils.h
@@ -15,7 +15,7 @@ namespace Botan {
namespace OS {
/**
-* Returns the OS assigned process ID, if available. Otherwise returns 0.
+* Returns the OS assigned process ID, if available. Otherwise throws.
*/
uint32_t get_process_id();