summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/rng
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/rng')
-rw-r--r--comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp112
-rw-r--r--comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h102
-rw-r--r--comm/third_party/botan/src/lib/rng/auto_rng/info.txt8
-rw-r--r--comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp87
-rw-r--r--comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h125
-rw-r--r--comm/third_party/botan/src/lib/rng/chacha_rng/info.txt10
-rw-r--r--comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp197
-rw-r--r--comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h150
-rw-r--r--comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt8
-rw-r--r--comm/third_party/botan/src/lib/rng/info.txt3
-rw-r--r--comm/third_party/botan/src/lib/rng/processor_rng/info.txt20
-rw-r--r--comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp157
-rw-r--r--comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h52
-rw-r--r--comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt13
-rw-r--r--comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp67
-rw-r--r--comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h68
-rw-r--r--comm/third_party/botan/src/lib/rng/rng.cpp91
-rw-r--r--comm/third_party/botan/src/lib/rng/rng.h297
-rw-r--r--comm/third_party/botan/src/lib/rng/stateful_rng/info.txt3
-rw-r--r--comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp190
-rw-r--r--comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h166
-rw-r--r--comm/third_party/botan/src/lib/rng/system_rng/info.txt18
-rw-r--r--comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp289
-rw-r--r--comm/third_party/botan/src/lib/rng/system_rng/system_rng.h43
24 files changed, 2276 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp
new file mode 100644
index 0000000000..a13429e9b5
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.cpp
@@ -0,0 +1,112 @@
+/*
+* (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>
+#include <botan/hmac_drbg.h>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#endif
+
+#if !defined(BOTAN_AUTO_RNG_HMAC)
+#error "No hash function defined for AutoSeeded_RNG in build.h (try enabling sha2_32)"
+#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 HMAC_DRBG(MessageAuthenticationCode::create_or_throw(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 HMAC_DRBG(MessageAuthenticationCode::create_or_throw(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 HMAC_DRBG(
+ MessageAuthenticationCode::create_or_throw(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 Internal_Error("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 uint8_t 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(uint8_t output[], size_t output_len)
+ {
+ m_rng->randomize_with_ts_input(output, output_len);
+ }
+
+void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t ad[], size_t ad_len)
+ {
+ m_rng->randomize_with_input(output, output_len, ad, ad_len);
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h
new file mode 100644
index 0000000000..8cb2c4a127
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/auto_rng/auto_rng.h
@@ -0,0 +1,102 @@
+/*
+* 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_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator
+ {
+ public:
+ void randomize(uint8_t out[], size_t len) override;
+
+ void randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len) override;
+
+ bool is_seeded() const override;
+
+ bool accepts_input() const override { return true; }
+
+ /**
+ * Mark state as requiring a reseed on next use
+ */
+ 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 uint8_t in[], size_t len) override;
+
+ std::string name() const override;
+
+ void clear() override;
+
+ /**
+ * Uses the system RNG (if available) or else a default group of
+ * entropy sources (all other systems) to gather seed material.
+ *
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed
+ */
+ AutoSeeded_RNG(size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Create an AutoSeeded_RNG which will get seed material from some other
+ * RNG instance. For example you could provide a reference to the system
+ * RNG or a hardware RNG.
+ *
+ * @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
+ */
+ AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Create an AutoSeeded_RNG which will get seed material from a set of
+ * entropy sources.
+ *
+ * @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
+ */
+ AutoSeeded_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Create an AutoSeeded_RNG which will get seed material from both an
+ * underlying RNG and a set of entropy sources.
+ *
+ * @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
+ */
+ 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/comm/third_party/botan/src/lib/rng/auto_rng/info.txt b/comm/third_party/botan/src/lib/rng/auto_rng/info.txt
new file mode 100644
index 0000000000..f1adcc8001
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/auto_rng/info.txt
@@ -0,0 +1,8 @@
+<defines>
+AUTO_SEEDING_RNG -> 20160821
+AUTO_RNG -> 20161126
+</defines>
+
+<requires>
+hmac_drbg
+</requires>
diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp
new file mode 100644
index 0000000000..3dc69ec1b8
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.cpp
@@ -0,0 +1,87 @@
+/*
+* ChaCha_RNG
+* (C) 2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/chacha_rng.h>
+
+namespace Botan {
+
+ChaCha_RNG::ChaCha_RNG() : Stateful_RNG()
+ {
+ m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
+ m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
+ clear();
+ }
+
+ChaCha_RNG::ChaCha_RNG(const secure_vector<uint8_t>& seed) : Stateful_RNG()
+ {
+ m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
+ m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
+ clear();
+ add_entropy(seed.data(), seed.size());
+ }
+
+ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval)
+ {
+ m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
+ m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
+ clear();
+ }
+
+ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, entropy_sources, reseed_interval)
+ {
+ m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
+ m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
+ clear();
+ }
+
+ChaCha_RNG::ChaCha_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval)
+ {
+ m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
+ m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
+ clear();
+ }
+
+void ChaCha_RNG::clear_state()
+ {
+ m_hmac->set_key(std::vector<uint8_t>(m_hmac->output_length(), 0x00));
+ m_chacha->set_key(m_hmac->final());
+ }
+
+void ChaCha_RNG::generate_output(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len)
+ {
+ if(input_len > 0)
+ {
+ update(input, input_len);
+ }
+
+ m_chacha->write_keystream(output, output_len);
+ }
+
+void ChaCha_RNG::update(const uint8_t input[], size_t input_len)
+ {
+ m_hmac->update(input, input_len);
+ m_chacha->set_key(m_hmac->final());
+
+ secure_vector<uint8_t> mac_key(m_hmac->output_length());
+ m_chacha->write_keystream(mac_key.data(), mac_key.size());
+ m_hmac->set_key(mac_key);
+ }
+
+size_t ChaCha_RNG::security_level() const
+ {
+ return 256;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h
new file mode 100644
index 0000000000..c50c2d0c25
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/chacha_rng/chacha_rng.h
@@ -0,0 +1,125 @@
+/*
+* ChaCha_RNG
+* (C) 2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_CHACHA_RNG_H_
+#define BOTAN_CHACHA_RNG_H_
+
+#include <botan/stateful_rng.h>
+#include <botan/stream_cipher.h>
+#include <botan/mac.h>
+
+namespace Botan {
+
+class Entropy_Sources;
+
+/**
+* ChaCha_RNG is a very fast but completely ad-hoc RNG created by
+* creating a 256-bit random value and using it as a key for ChaCha20.
+*
+* The RNG maintains two 256-bit keys, one for HMAC_SHA256 (HK) and the
+* other for ChaCha20 (CK). To compute a new key in response to
+* reseeding request or add_entropy calls, ChaCha_RNG computes
+* CK' = HMAC_SHA256(HK, input_material)
+* Then a new HK' is computed by running ChaCha20 with the new key to
+* output 32 bytes:
+* HK' = ChaCha20(CK')
+*
+* Now output can be produced by continuing to produce output with ChaCha20
+* under CK'
+*
+* The first HK (before seeding occurs) is taken as the all zero value.
+*
+* @warning This RNG construction is probably fine but is non-standard.
+* The primary reason to use it is in cases where the other RNGs are
+* not fast enough.
+*/
+class BOTAN_PUBLIC_API(2,3) ChaCha_RNG final : public Stateful_RNG
+ {
+ public:
+ /**
+ * Automatic reseeding is disabled completely, as it has 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.
+ */
+ ChaCha_RNG();
+
+ /**
+ * Provide an initial seed to the RNG, without providing an
+ * underlying RNG or entropy source. Automatic reseeding is
+ * disabled completely, as it has 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.
+ *
+ * @param seed the seed material, should be at least 256 bits
+ */
+ ChaCha_RNG(const secure_vector<uint8_t>& seed);
+
+ /**
+ * Automatic reseeding from @p underlying_rng will take place after
+ * @p reseed_interval many requests or after a fork was detected.
+ *
+ * @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
+ */
+ ChaCha_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Automatic reseeding from @p entropy_sources will take place after
+ * @p reseed_interval many requests or after a fork was detected.
+ *
+ * @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.
+ */
+ ChaCha_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Automatic reseeding from @p underlying_rng and @p entropy_sources
+ * will take place after @p reseed_interval many requests or after
+ * a fork was detected.
+ *
+ * @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.
+ */
+ ChaCha_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ std::string name() const override { return "ChaCha_RNG"; }
+
+ size_t security_level() const override;
+
+ size_t max_number_of_bytes_per_request() const override { return 0; }
+
+ private:
+ void update(const uint8_t input[], size_t input_len) override;
+
+ void generate_output(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len) override;
+
+ void clear_state() override;
+
+ std::unique_ptr<MessageAuthenticationCode> m_hmac;
+ std::unique_ptr<StreamCipher> m_chacha;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt b/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt
new file mode 100644
index 0000000000..3f51bf4d0e
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/chacha_rng/info.txt
@@ -0,0 +1,10 @@
+<defines>
+CHACHA_RNG -> 20170728
+</defines>
+
+<requires>
+hmac
+sha2_32
+chacha
+stateful_rng
+</requires>
diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp
new file mode 100644
index 0000000000..2b66a839c3
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp
@@ -0,0 +1,197 @@
+/*
+* HMAC_DRBG
+* (C) 2014,2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/hmac_drbg.h>
+#include <algorithm>
+
+namespace Botan {
+
+namespace {
+
+size_t hmac_drbg_security_level(size_t mac_output_length)
+ {
+ // security strength of the hash function
+ // for pre-image resistance (see NIST SP 800-57)
+ // SHA-160: 128 bits
+ // SHA-224, SHA-512/224: 192 bits,
+ // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits
+ // NIST SP 800-90A only supports up to 256 bits though
+
+ if(mac_output_length < 32)
+ {
+ return (mac_output_length - 4) * 8;
+ }
+ else
+ {
+ return 32 * 8;
+ }
+ }
+
+void check_limits(size_t reseed_interval,
+ size_t max_number_of_bytes_per_request)
+ {
+ // SP800-90A permits up to 2^48, but it is not usable on 32 bit
+ // platforms, so we only allow up to 2^24, which is still reasonably high
+ if(reseed_interval == 0 || reseed_interval > static_cast<size_t>(1) << 24)
+ {
+ throw Invalid_Argument("Invalid value for reseed_interval");
+ }
+
+ if(max_number_of_bytes_per_request == 0 || max_number_of_bytes_per_request > 64 * 1024)
+ {
+ throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request");
+ }
+ }
+
+}
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval,
+ size_t max_number_of_bytes_per_request) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_mac(std::move(prf)),
+ m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
+ m_security_level(hmac_drbg_security_level(m_mac->output_length()))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+
+ check_limits(reseed_interval, max_number_of_bytes_per_request);
+
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval,
+ size_t max_number_of_bytes_per_request) :
+ Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
+ m_mac(std::move(prf)),
+ m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
+ m_security_level(hmac_drbg_security_level(m_mac->output_length()))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+
+ check_limits(reseed_interval, max_number_of_bytes_per_request);
+
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval,
+ size_t max_number_of_bytes_per_request) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_mac(std::move(prf)),
+ m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
+ m_security_level(hmac_drbg_security_level(m_mac->output_length()))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+
+ check_limits(reseed_interval, max_number_of_bytes_per_request);
+
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_mac(std::move(prf)),
+ m_max_number_of_bytes_per_request(64*1024),
+ m_security_level(hmac_drbg_security_level(m_mac->output_length()))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash) :
+ Stateful_RNG(),
+ m_mac(MessageAuthenticationCode::create_or_throw("HMAC(" + hmac_hash + ")")),
+ m_max_number_of_bytes_per_request(64 * 1024),
+ m_security_level(hmac_drbg_security_level(m_mac->output_length()))
+ {
+ clear();
+ }
+
+void HMAC_DRBG::clear_state()
+ {
+ if(m_V.size() == 0)
+ {
+ const size_t output_length = m_mac->output_length();
+ m_V.resize(output_length);
+ }
+
+ for(size_t i = 0; i != m_V.size(); ++i)
+ m_V[i] = 0x01;
+ m_mac->set_key(std::vector<uint8_t>(m_V.size(), 0x00));
+ }
+
+std::string HMAC_DRBG::name() const
+ {
+ return "HMAC_DRBG(" + m_mac->name() + ")";
+ }
+
+/*
+* HMAC_DRBG generation
+* See NIST SP800-90A section 10.1.2.5
+*/
+void HMAC_DRBG::generate_output(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len)
+ {
+ if(input_len > 0)
+ {
+ update(input, input_len);
+ }
+
+ while(output_len > 0)
+ {
+ 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);
+
+ output += to_copy;
+ output_len -= to_copy;
+ }
+
+ update(input, input_len);
+ }
+
+/*
+* Reset V and the mac key with new values
+* See NIST SP800-90A section 10.1.2.2
+*/
+void HMAC_DRBG::update(const uint8_t input[], size_t input_len)
+ {
+ secure_vector<uint8_t> T(m_V.size());
+ m_mac->update(m_V);
+ m_mac->update(0x00);
+ m_mac->update(input, input_len);
+ m_mac->final(T.data());
+ m_mac->set_key(T);
+
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
+
+ if(input_len > 0)
+ {
+ m_mac->update(m_V);
+ m_mac->update(0x01);
+ m_mac->update(input, input_len);
+ m_mac->final(T.data());
+ m_mac->set_key(T);
+
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
+ }
+ }
+
+size_t HMAC_DRBG::security_level() const
+ {
+ return m_security_level;
+ }
+}
diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h
new file mode 100644
index 0000000000..a4c288c74b
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/hmac_drbg.h
@@ -0,0 +1,150 @@
+/*
+* HMAC_DRBG (SP800-90A)
+* (C) 2014,2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_HMAC_DRBG_H_
+#define BOTAN_HMAC_DRBG_H_
+
+#include <botan/stateful_rng.h>
+#include <botan/mac.h>
+
+namespace Botan {
+
+class Entropy_Sources;
+
+/**
+* HMAC_DRBG from NIST SP800-90A
+*/
+class BOTAN_PUBLIC_API(2,0) HMAC_DRBG final : public Stateful_RNG
+ {
+ public:
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding is disabled completely, as it has 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.
+ */
+ explicit HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf);
+
+ /**
+ * Constructor taking a string for the hash
+ */
+ explicit HMAC_DRBG(const std::string& hmac_hash);
+
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding from @p underlying_rng will take place after
+ * @p reseed_interval many requests or after a fork was detected.
+ *
+ * @param prf MAC to use as a PRF
+ * @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 (max. 2^24)
+ * @param max_number_of_bytes_per_request requests that are in size higher
+ * than max_number_of_bytes_per_request are treated as if multiple single
+ * requests of max_number_of_bytes_per_request size had been made.
+ * In theory SP 800-90A requires that we reject any request for a DRBG
+ * output longer than max_number_of_bytes_per_request. To avoid inconveniencing
+ * the caller who wants an output larger than max_number_of_bytes_per_request,
+ * instead treat these requests as if multiple requests of
+ * max_number_of_bytes_per_request size had been made. NIST requires for
+ * HMAC_DRBG that every implementation set a value no more than 2**19 bits
+ * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for
+ * example every 512 bit automatic reseeding occurs.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL,
+ size_t max_number_of_bytes_per_request = 64 * 1024);
+
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding from @p entropy_sources will take place after
+ * @p reseed_interval many requests or after a fork was detected.
+ *
+ * @param prf MAC to use as a PRF
+ * @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 (max. 2^24)
+ * @param max_number_of_bytes_per_request requests that are in size higher
+ * than max_number_of_bytes_per_request are treated as if multiple single
+ * requests of max_number_of_bytes_per_request size had been made.
+ * In theory SP 800-90A requires that we reject any request for a DRBG
+ * output longer than max_number_of_bytes_per_request. To avoid inconveniencing
+ * the caller who wants an output larger than max_number_of_bytes_per_request,
+ * instead treat these requests as if multiple requests of
+ * max_number_of_bytes_per_request size had been made. NIST requires for
+ * HMAC_DRBG that every implementation set a value no more than 2**19 bits
+ * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for
+ * example every 512 bit automatic reseeding occurs.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL,
+ size_t max_number_of_bytes_per_request = 64 * 1024);
+
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding from @p underlying_rng and @p entropy_sources
+ * will take place after @p reseed_interval many requests or after
+ * a fork was detected.
+ *
+ * @param prf MAC to use as a PRF
+ * @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 (max. 2^24)
+ * @param max_number_of_bytes_per_request requests that are in size higher
+ * than max_number_of_bytes_per_request are treated as if multiple single
+ * requests of max_number_of_bytes_per_request size had been made.
+ * In theory SP 800-90A requires that we reject any request for a DRBG
+ * output longer than max_number_of_bytes_per_request. To avoid inconveniencing
+ * the caller who wants an output larger than max_number_of_bytes_per_request,
+ * instead treat these requests as if multiple requests of
+ * max_number_of_bytes_per_request size had been made. NIST requires for
+ * HMAC_DRBG that every implementation set a value no more than 2**19 bits
+ * (or 64 KiB). Together with @p reseed_interval = 1 you can enforce that for
+ * example every 512 bit automatic reseeding occurs.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL,
+ size_t max_number_of_bytes_per_request = 64 * 1024);
+
+ std::string name() const override;
+
+ size_t security_level() const override;
+
+ size_t max_number_of_bytes_per_request() const override
+ { return m_max_number_of_bytes_per_request; }
+
+ private:
+ void update(const uint8_t input[], size_t input_len) override;
+
+ void generate_output(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len) override;
+
+ void clear_state() override;
+
+ std::unique_ptr<MessageAuthenticationCode> m_mac;
+ secure_vector<uint8_t> m_V;
+ const size_t m_max_number_of_bytes_per_request;
+ const size_t m_security_level;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt b/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt
new file mode 100644
index 0000000000..a8922bdf0e
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/hmac_drbg/info.txt
@@ -0,0 +1,8 @@
+<defines>
+HMAC_DRBG -> 20140319
+</defines>
+
+<requires>
+hmac
+stateful_rng
+</requires>
diff --git a/comm/third_party/botan/src/lib/rng/info.txt b/comm/third_party/botan/src/lib/rng/info.txt
new file mode 100644
index 0000000000..4c88ba3826
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/info.txt
@@ -0,0 +1,3 @@
+<requires>
+entropy
+</requires>
diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/info.txt b/comm/third_party/botan/src/lib/rng/processor_rng/info.txt
new file mode 100644
index 0000000000..61d10f11b4
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/processor_rng/info.txt
@@ -0,0 +1,20 @@
+<defines>
+PROCESSOR_RNG -> 20200508
+</defines>
+
+<cc>
+gcc
+clang
+icc
+msvc
+</cc>
+
+<arch>
+x86_32
+x86_64
+ppc64
+</arch>
+
+<isa>
+ppc64:power9
+</isa>
diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp
new file mode 100644
index 0000000000..ca52d05e67
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.cpp
@@ -0,0 +1,157 @@
+/*
+* (C) 2016,2019,2020 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/processor_rng.h>
+#include <botan/loadstor.h>
+#include <botan/cpuid.h>
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY) && !defined(BOTAN_USE_GCC_INLINE_ASM)
+ #include <immintrin.h>
+#endif
+
+namespace Botan {
+
+namespace {
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ /*
+ * According to Intel, RDRAND is guaranteed to generate a random
+ * number within 10 retries on a working CPU
+ */
+ const size_t HWRNG_RETRIES = 10;
+
+#else
+ /*
+ * Lacking specific guidance we give the CPU quite a bit of leeway
+ */
+ const size_t HWRNG_RETRIES = 512;
+#endif
+
+#if defined(BOTAN_TARGET_ARCH_IS_X86_32)
+ typedef uint32_t hwrng_output;
+#else
+ typedef uint64_t hwrng_output;
+#endif
+
+hwrng_output read_hwrng(bool& success)
+ {
+ hwrng_output output = 0;
+ success = false;
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ int cf = 0;
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+ // same asm seq works for 32 and 64 bit
+ asm volatile("rdrand %0; adcl $0,%1" :
+ "=r" (output), "=r" (cf) : "0" (output), "1" (cf) : "cc");
+#elif defined(BOTAN_TARGET_ARCH_IS_X86_32)
+ cf = _rdrand32_step(&output);
+#else
+ cf = _rdrand64_step(&output);
+#endif
+ success = (1 == cf);
+
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+
+ /*
+ DARN indicates error by returning 0xFF..FF, ie is biased. Which is crazy.
+ Avoid the bias by invoking it twice and, assuming both succeed, returning the
+ XOR of the two results, which should unbias the output.
+ */
+ uint64_t output2 = 0;
+ // DARN codes are 0: 32-bit conditioned, 1: 64-bit conditioned, 2: 64-bit raw (ala RDSEED)
+ asm volatile("darn %0, 1" : "=r" (output));
+ asm volatile("darn %0, 1" : "=r" (output2));
+
+ if((~output) != 0 && (~output2) != 0)
+ {
+ output ^= output2;
+ success = true;
+ }
+
+#endif
+
+ if(success)
+ return output;
+
+ return 0;
+ }
+
+hwrng_output read_hwrng()
+ {
+ for(size_t i = 0; i < HWRNG_RETRIES; ++i)
+ {
+ bool success = false;
+ hwrng_output output = read_hwrng(success);
+
+ if(success)
+ return output;
+ }
+
+ throw PRNG_Unseeded("Processor RNG instruction failed to produce output within expected iterations");
+ }
+
+}
+
+//static
+bool Processor_RNG::available()
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ return CPUID::has_rdrand();
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ return CPUID::has_darn_rng();
+#else
+ return false;
+#endif
+ }
+
+std::string Processor_RNG::name() const
+ {
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ return "rdrand";
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ return "darn";
+#else
+ return "hwrng";
+#endif
+ }
+
+void Processor_RNG::randomize(uint8_t out[], size_t out_len)
+ {
+ while(out_len >= sizeof(hwrng_output))
+ {
+ const hwrng_output r = read_hwrng();
+ store_le(r, out);
+ out += sizeof(hwrng_output);
+ out_len -= sizeof(hwrng_output);
+ }
+
+ if(out_len > 0) // at most sizeof(hwrng_output)-1
+ {
+ const hwrng_output r = read_hwrng();
+ for(size_t i = 0; i != out_len; ++i)
+ out[i] = get_byte(i, r);
+ }
+ }
+
+Processor_RNG::Processor_RNG()
+ {
+ if(!Processor_RNG::available())
+ throw Invalid_State("Current CPU does not support RNG instruction");
+ }
+
+void Processor_RNG::add_entropy(const uint8_t[], size_t)
+ {
+ /* no way to add entropy */
+ }
+
+size_t Processor_RNG::reseed(Entropy_Sources&, size_t, std::chrono::milliseconds)
+ {
+ /* no way to add entropy */
+ return 0;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h
new file mode 100644
index 0000000000..5900e386e0
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/processor_rng/processor_rng.h
@@ -0,0 +1,52 @@
+/*
+* (C) 2016,2019,2020 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_RNG_PROCESSOR_RNG_H_
+#define BOTAN_RNG_PROCESSOR_RNG_H_
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+/**
+* Directly invokes a CPU specific instruction to generate random numbers.
+* On x86, the RDRAND instruction is used.
+* on POWER, the DARN instruction is used.
+*/
+class BOTAN_PUBLIC_API(2,15) Processor_RNG final : public Hardware_RNG
+ {
+ public:
+ /**
+ * Constructor will throw if CPU does not have RDRAND bit set
+ */
+ Processor_RNG();
+
+ /**
+ * Return true if RNG instruction is available on the current processor
+ */
+ static bool available();
+
+ bool accepts_input() const override { return false; }
+ bool is_seeded() const override { return true; }
+
+ void randomize(uint8_t out[], size_t out_len) override;
+
+ /*
+ * No way to provide entropy to RDRAND generator, so add_entropy is ignored
+ */
+ void add_entropy(const uint8_t[], size_t) override;
+
+ /*
+ * No way to reseed processor provided generator, so reseed is ignored
+ */
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override;
+
+ std::string name() const override;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt b/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt
new file mode 100644
index 0000000000..5cc616deae
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/info.txt
@@ -0,0 +1,13 @@
+<defines>
+RDRAND_RNG -> 20160619
+</defines>
+
+<requires>
+processor_rng
+</requires>
+
+# Avoid building RDRAND_RNG on non-x86 since that would be confusing
+<arch>
+x86_32
+x86_64
+</arch>
diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp
new file mode 100644
index 0000000000..fade5a1992
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp
@@ -0,0 +1,67 @@
+/*
+* RDRAND RNG
+* (C) 2016,2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/rdrand_rng.h>
+#include <botan/processor_rng.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+void RDRAND_RNG::randomize(uint8_t out[], size_t out_len)
+ {
+ Processor_RNG rng;
+ rng.randomize(out, out_len);
+ }
+
+RDRAND_RNG::RDRAND_RNG()
+ {
+ // Will throw if instruction is not available
+ Processor_RNG rng;
+ }
+
+//static
+bool RDRAND_RNG::available()
+ {
+ return Processor_RNG::available();
+ }
+
+//static
+uint32_t RDRAND_RNG::rdrand()
+ {
+ Processor_RNG rng;
+
+ for(;;)
+ {
+ try
+ {
+ uint8_t out[4];
+ rng.randomize(out, 4);
+ return load_le<uint32_t>(out, 0);
+ }
+ catch(PRNG_Unseeded&) {}
+ }
+ }
+
+//static
+uint32_t RDRAND_RNG::rdrand_status(bool& ok)
+ {
+ ok = false;
+ Processor_RNG rng;
+
+ try
+ {
+ uint8_t out[4];
+ rng.randomize(out, 4);
+ ok = true;
+ return load_le<uint32_t>(out, 0);
+ }
+ catch(PRNG_Unseeded&) {}
+
+ return 0;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h
new file mode 100644
index 0000000000..1b6977eac3
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/rdrand_rng/rdrand_rng.h
@@ -0,0 +1,68 @@
+/*
+* RDRAND RNG
+* (C) 2016,2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_RNG_RDRAND_H_
+#define BOTAN_RNG_RDRAND_H_
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+class BOTAN_PUBLIC_API(2,0) RDRAND_RNG final : public Hardware_RNG
+ {
+ public:
+ /**
+ * Constructor will throw if CPU does not have RDRAND bit set
+ */
+ BOTAN_DEPRECATED("Use Processor_RNG instead") RDRAND_RNG();
+
+ /**
+ * Return true if RDRAND is available on the current processor
+ */
+ static bool available();
+
+ bool accepts_input() const override { return false; }
+
+ /**
+ * Uses RDRAND to produce output
+ */
+ void randomize(uint8_t out[], size_t out_len) override;
+
+ /*
+ * No way to provide entropy to RDRAND generator, so add_entropy is ignored
+ */
+ void add_entropy(const uint8_t[], size_t) override
+ { /* no op */ }
+
+ /*
+ * No way to reseed RDRAND generator, so reseed is ignored
+ */
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override
+ { return 0; /* no op */ }
+
+ std::string name() const override { return "RDRAND"; }
+
+ bool is_seeded() const override { return true; }
+
+ /**
+ * On correctly working hardware, RDRAND is always supposed to
+ * succeed within a set number of retries. If after that many
+ * retries RDRAND has still not suceeded, sets ok = false and
+ * returns 0.
+ */
+ static uint32_t BOTAN_DEPRECATED("Use Processor_RNG::randomize") rdrand_status(bool& ok);
+
+ /*
+ * Calls RDRAND until it succeeds, this could hypothetically
+ * loop forever on broken hardware.
+ */
+ static uint32_t BOTAN_DEPRECATED("Use Processor_RNG::randomize") rdrand();
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/rng.cpp b/comm/third_party/botan/src/lib/rng/rng.cpp
new file mode 100644
index 0000000000..743f7c7aa2
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/rng.cpp
@@ -0,0 +1,91 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/rng.h>
+#include <botan/entropy_src.h>
+#include <botan/loadstor.h>
+#include <botan/internal/os_utils.h>
+
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+ #include <botan/auto_rng.h>
+#endif
+
+namespace Botan {
+
+void RandomNumberGenerator::randomize_with_ts_input(uint8_t output[], size_t output_len)
+ {
+ if(this->accepts_input())
+ {
+ /*
+ Form additional input which is provided to the PRNG implementation
+ to paramaterize the KDF output.
+ */
+ uint8_t additional_input[16] = { 0 };
+ store_le(OS::get_system_timestamp_ns(), additional_input);
+ store_le(OS::get_high_resolution_clock(), additional_input + 8);
+
+ this->randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
+ }
+ else
+ {
+ this->randomize(output, output_len);
+ }
+ }
+
+void RandomNumberGenerator::randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len)
+ {
+ this->add_entropy(input, input_len);
+ this->randomize(output, output_len);
+ }
+
+size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ if(this->accepts_input())
+ {
+ return srcs.poll(*this, poll_bits, poll_timeout);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
+ {
+ if(this->accepts_input())
+ {
+ secure_vector<uint8_t> 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 Not_Implemented("make_rng failed, no AutoSeeded_RNG in this build");
+#endif
+ }
+
+#if defined(BOTAN_TARGET_OS_HAS_THREADS)
+
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+Serialized_RNG::Serialized_RNG() : m_rng(new AutoSeeded_RNG) {}
+#else
+Serialized_RNG::Serialized_RNG()
+ {
+ throw Not_Implemented("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build");
+ }
+#endif
+
+#endif
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/rng.h b/comm/third_party/botan/src/lib/rng/rng.h
new file mode 100644
index 0000000000..54a8ea8319
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/rng.h
@@ -0,0 +1,297 @@
+/*
+* Random Number Generator base classes
+* (C) 1999-2009,2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_
+#define BOTAN_RANDOM_NUMBER_GENERATOR_H_
+
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <botan/mutex.h>
+#include <type_traits>
+#include <chrono>
+#include <string>
+
+namespace Botan {
+
+class Entropy_Sources;
+
+/**
+* An interface to a cryptographic random number generator
+*/
+class BOTAN_PUBLIC_API(2,0) RandomNumberGenerator
+ {
+ public:
+ virtual ~RandomNumberGenerator() = default;
+
+ RandomNumberGenerator() = default;
+
+ /*
+ * Never copy a RNG, create a new one
+ */
+ RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
+ RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
+
+ /**
+ * Randomize a byte array.
+ * @param output the byte array to hold the random output.
+ * @param length the length of the byte array output in bytes.
+ */
+ virtual void randomize(uint8_t output[], size_t length) = 0;
+
+ /**
+ * Returns false if it is known that this RNG object is not able to accept
+ * externally provided inputs (via add_entropy, randomize_with_input, etc).
+ * In this case, any such provided inputs are ignored.
+ *
+ * If this function returns true, then inputs may or may not be accepted.
+ */
+ virtual bool accepts_input() const = 0;
+
+ /**
+ * 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 input a byte array containg the entropy to be added
+ * @param length the length of the byte array in
+ */
+ virtual void add_entropy(const uint8_t input[], size_t length) = 0;
+
+ /**
+ * Incorporate some additional data into the RNG state.
+ */
+ template<typename T> void add_entropy_T(const T& t)
+ {
+ static_assert(std::is_standard_layout<T>::value && std::is_trivial<T>::value, "add_entropy_T data must be POD");
+ 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, 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.
+ *
+ * @param output buffer to hold the random output
+ * @param output_len size of the output buffer in bytes
+ * @param input entropy buffer to incorporate
+ * @param input_len size of the input buffer in bytes
+ */
+ virtual void randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t 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 the
+ * extra 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(uint8_t output[], size_t output_len);
+
+ /**
+ * @return the name of this RNG type
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ * Clear all internally held values of this RNG
+ * @post is_seeded() == false
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Check whether this RNG is seeded.
+ * @return true if this RNG was already seeded, false otherwise.
+ */
+ virtual bool is_seeded() const = 0;
+
+ /**
+ * Poll provided sources for up to poll_bits bits of entropy
+ * or until the timeout expires. Returns estimate of the number
+ * of bits collected.
+ */
+ 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 by reading specified bits from the RNG
+ */
+ virtual void reseed_from_rng(RandomNumberGenerator& rng,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS);
+
+ // Some utility functions built on the interface above:
+
+ /**
+ * Return a random vector
+ * @param bytes number of bytes in the result
+ * @return randomized vector of length bytes
+ */
+ secure_vector<uint8_t> random_vec(size_t bytes)
+ {
+ secure_vector<uint8_t> output;
+ random_vec(output, bytes);
+ return output;
+ }
+
+ template<typename Alloc>
+ void random_vec(std::vector<uint8_t, Alloc>& v, size_t bytes)
+ {
+ v.resize(bytes);
+ this->randomize(v.data(), v.size());
+ }
+
+ /**
+ * Return a random byte
+ * @return random byte
+ */
+ uint8_t next_byte()
+ {
+ uint8_t b;
+ this->randomize(&b, 1);
+ return b;
+ }
+
+ /**
+ * @return a random byte that is greater than zero
+ */
+ uint8_t next_nonzero_byte()
+ {
+ uint8_t b = this->next_byte();
+ while(b == 0)
+ b = this->next_byte();
+ return b;
+ }
+
+ /**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.8.0
+ * Use AutoSeeded_RNG instead
+ */
+ BOTAN_DEPRECATED("Use AutoSeeded_RNG")
+ static RandomNumberGenerator* make_rng();
+ };
+
+/**
+* Convenience typedef
+*/
+typedef RandomNumberGenerator RNG;
+
+/**
+* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG)
+*/
+class BOTAN_PUBLIC_API(2,0) Hardware_RNG : public RandomNumberGenerator
+ {
+ public:
+ virtual void clear() final override { /* no way to clear state of hardware RNG */ }
+ };
+
+/**
+* Null/stub RNG - fails if you try to use it for anything
+* This is not generally useful except for in certain tests
+*/
+class BOTAN_PUBLIC_API(2,0) Null_RNG final : public RandomNumberGenerator
+ {
+ public:
+ bool is_seeded() const override { return false; }
+
+ bool accepts_input() const override { return false; }
+
+ void clear() override {}
+
+ void randomize(uint8_t[], size_t) override
+ {
+ throw PRNG_Unseeded("Null_RNG called");
+ }
+
+ void add_entropy(const uint8_t[], size_t) override {}
+
+ std::string name() const override { return "Null_RNG"; }
+ };
+
+#if defined(BOTAN_TARGET_OS_HAS_THREADS)
+/**
+* Wraps access to a RNG in a mutex
+* Note that most of the time it's much better to use a RNG per thread
+* otherwise the RNG will act as an unnecessary contention point
+*
+* Since 2.16.0 all Stateful_RNG instances have an internal lock, so
+* this class is no longer needed. It will be removed in a future major
+* release.
+*/
+class BOTAN_PUBLIC_API(2,0) Serialized_RNG final : public RandomNumberGenerator
+ {
+ public:
+ void randomize(uint8_t out[], size_t len) override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ m_rng->randomize(out, len);
+ }
+
+ bool accepts_input() const override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ return m_rng->accepts_input();
+ }
+
+ bool is_seeded() const override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ return m_rng->is_seeded();
+ }
+
+ void clear() override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ m_rng->clear();
+ }
+
+ std::string name() const override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ return m_rng->name();
+ }
+
+ 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
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ return m_rng->reseed(src, poll_bits, poll_timeout);
+ }
+
+ void add_entropy(const uint8_t in[], size_t len) override
+ {
+ lock_guard_type<mutex_type> lock(m_mutex);
+ m_rng->add_entropy(in, len);
+ }
+
+ BOTAN_DEPRECATED("Use Serialized_RNG(new AutoSeeded_RNG) instead") Serialized_RNG();
+
+ /*
+ * Since 2.16.0 this is no longer needed for any RNG type. This
+ * class will be removed in a future major release.
+ */
+ explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {}
+ private:
+ mutable mutex_type m_mutex;
+ std::unique_ptr<RandomNumberGenerator> m_rng;
+ };
+#endif
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt b/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt
new file mode 100644
index 0000000000..edc2d91694
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/stateful_rng/info.txt
@@ -0,0 +1,3 @@
+<defines>
+STATEFUL_RNG -> 20160819
+</defines>
diff --git a/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp
new file mode 100644
index 0000000000..c7b3484ee0
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.cpp
@@ -0,0 +1,190 @@
+/*
+* (C) 2016,2020 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>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#endif
+
+namespace Botan {
+
+void Stateful_RNG::clear()
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+ m_reseed_counter = 0;
+ m_last_pid = 0;
+ clear_state();
+ }
+
+void Stateful_RNG::force_reseed()
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+ m_reseed_counter = 0;
+ }
+
+bool Stateful_RNG::is_seeded() const
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+ return m_reseed_counter > 0;
+ }
+
+void Stateful_RNG::add_entropy(const uint8_t input[], size_t input_len)
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+
+ update(input, input_len);
+
+ if(8*input_len >= security_level())
+ {
+ reset_reseed_counter();
+ }
+ }
+
+void Stateful_RNG::initialize_with(const uint8_t input[], size_t len)
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+
+ clear();
+ add_entropy(input, len);
+ }
+
+void Stateful_RNG::randomize(uint8_t output[], size_t output_len)
+ {
+ randomize_with_input(output, output_len, nullptr, 0);
+ }
+
+void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len)
+ {
+ uint8_t additional_input[20] = { 0 };
+
+ store_le(OS::get_high_resolution_clock(), additional_input);
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ System_RNG system_rng;
+ system_rng.randomize(additional_input + 8, sizeof(additional_input) - 8);
+#else
+ store_le(OS::get_system_timestamp_ns(), additional_input + 8);
+ store_le(OS::get_process_id(), additional_input + 16);
+#endif
+
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
+ }
+
+void Stateful_RNG::randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len)
+ {
+ if(output_len == 0)
+ return;
+
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+
+ const size_t max_per_request = max_number_of_bytes_per_request();
+
+ if(max_per_request == 0) // no limit
+ {
+ reseed_check();
+ this->generate_output(output, output_len, input, input_len);
+ }
+ else
+ {
+ while(output_len > 0)
+ {
+ const size_t this_req = std::min(max_per_request, output_len);
+
+ /*
+ * We split the request into several requests to the underlying DRBG but
+ * pass the input to each invocation. It might be more sensible to only
+ * provide it for the first invocation, however between 2.0 and 2.15
+ * HMAC_DRBG always provided it for all requests so retain that here.
+ */
+
+ reseed_check();
+ this->generate_output(output, this_req, input, input_len);
+
+ output += this_req;
+ output_len -= this_req;
+ }
+ }
+ }
+
+size_t Stateful_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+
+ const size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout);
+
+ if(bits_collected >= security_level())
+ {
+ reset_reseed_counter();
+ }
+
+ return bits_collected;
+ }
+
+void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
+ {
+ lock_guard_type<recursive_mutex_type> lock(m_mutex);
+
+ RandomNumberGenerator::reseed_from_rng(rng, poll_bits);
+
+ if(poll_bits >= security_level())
+ {
+ reset_reseed_counter();
+ }
+ }
+
+void Stateful_RNG::reset_reseed_counter()
+ {
+ // Lock is held whenever this function is called
+ m_reseed_counter = 1;
+ }
+
+void Stateful_RNG::reseed_check()
+ {
+ // Lock is held whenever this function is called
+
+ 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 Invalid_State("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/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h
new file mode 100644
index 0000000000..e1311fcc9f
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/stateful_rng/stateful_rng.h
@@ -0,0 +1,166 @@
+/*
+* (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>
+#include <botan/mutex.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_PUBLIC_API(2,0) Stateful_RNG : public RandomNumberGenerator
+ {
+ public:
+ /**
+ * @param 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
+ */
+ 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)
+ {}
+
+ /**
+ * @param 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
+ */
+ Stateful_RNG(RandomNumberGenerator& rng, size_t reseed_interval) :
+ m_underlying_rng(&rng),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ /**
+ * @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
+ */
+ 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 uint8_t input[], size_t length);
+
+ bool is_seeded() const override final;
+
+ bool accepts_input() const override final { return true; }
+
+ /**
+ * 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;
+
+ void add_entropy(const uint8_t input[], size_t input_len) override final;
+
+ void randomize(uint8_t output[], size_t output_len) override final;
+
+ void randomize_with_input(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len) override final;
+
+ /**
+ * Overrides default implementation and also includes the current
+ * process ID and the reseed counter.
+ */
+ void randomize_with_ts_input(uint8_t 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;
+
+ /**
+ * Some DRBGs have a notion of the maximum number of bytes per
+ * request. Longer requests (to randomize) will be treated as
+ * multiple requests, and may initiate reseeding multiple times,
+ * depending on the values of max_number_of_bytes_per_request and
+ * reseed_interval(). This function returns zero if the RNG in
+ * question does not have such a notion.
+ *
+ * @return max number of bytes per request (or zero)
+ */
+ virtual size_t max_number_of_bytes_per_request() const = 0;
+
+ size_t reseed_interval() const { return m_reseed_interval; }
+
+ void clear() override final;
+
+ protected:
+ void reseed_check();
+
+ virtual void generate_output(uint8_t output[], size_t output_len,
+ const uint8_t input[], size_t input_len) = 0;
+
+ virtual void update(const uint8_t input[], size_t input_len) = 0;
+
+ virtual void clear_state() = 0;
+
+ private:
+ void reset_reseed_counter();
+
+ mutable recursive_mutex_type m_mutex;
+
+ // 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;
+ uint32_t m_last_pid = 0;
+
+ /*
+ * Set to 1 after a successful 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;
+ };
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/rng/system_rng/info.txt b/comm/third_party/botan/src/lib/rng/system_rng/info.txt
new file mode 100644
index 0000000000..e77328b820
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/system_rng/info.txt
@@ -0,0 +1,18 @@
+<defines>
+SYSTEM_RNG -> 20141202
+</defines>
+
+<os_features>
+dev_random,posix1
+arc4random
+rtlgenrandom
+crypto_ng
+</os_features>
+
+<libs>
+uwp -> bcrypt
+</libs>
+
+<requires>
+rtlgenrandom?dyn_load
+</requires>
diff --git a/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp
new file mode 100644
index 0000000000..0c5641e60d
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.cpp
@@ -0,0 +1,289 @@
+/*
+* System RNG
+* (C) 2014,2015,2017,2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/system_rng.h>
+
+#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
+ #include <botan/dyn_load.h>
+ #define NOMINMAX 1
+ #define _WINSOCKAPI_ // stop windows.h including winsock.h
+ #include <windows.h>
+
+#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
+ #include <bcrypt.h>
+
+#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
+ #include <stdlib.h>
+
+#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
+ #include <sys/random.h>
+ #include <errno.h>
+
+#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <errno.h>
+#endif
+
+namespace Botan {
+
+namespace {
+
+#if defined(BOTAN_TARGET_OS_HAS_RTLGENRANDOM)
+
+class System_RNG_Impl final : public RandomNumberGenerator
+ {
+ public:
+ System_RNG_Impl() : m_advapi("advapi32.dll")
+ {
+ // This throws if the function is not found
+ m_rtlgenrandom = m_advapi.resolve<RtlGenRandom_fptr>("SystemFunction036");
+ }
+
+ void randomize(uint8_t buf[], size_t len) override
+ {
+ bool success = m_rtlgenrandom(buf, ULONG(len)) == TRUE;
+ if(!success)
+ throw System_Error("RtlGenRandom failed");
+ }
+
+ void add_entropy(const uint8_t[], size_t) override { /* ignored */ }
+ bool is_seeded() const override { return true; }
+ bool accepts_input() const override { return false; }
+ void clear() override { /* not possible */ }
+ std::string name() const override { return "RtlGenRandom"; }
+ private:
+ // Use type BYTE instead of BOOLEAN because of a naming conflict
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694(v=vs.85).aspx
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
+ using RtlGenRandom_fptr = BYTE (NTAPI *)(PVOID, ULONG);
+
+ Dynamically_Loaded_Library m_advapi;
+ RtlGenRandom_fptr m_rtlgenrandom;
+ };
+
+#elif defined(BOTAN_TARGET_OS_HAS_CRYPTO_NG)
+
+class System_RNG_Impl final : public RandomNumberGenerator
+ {
+ public:
+ System_RNG_Impl()
+ {
+ NTSTATUS ret = ::BCryptOpenAlgorithmProvider(&m_prov,
+ BCRYPT_RNG_ALGORITHM,
+ MS_PRIMITIVE_PROVIDER, 0);
+ if(ret != STATUS_SUCCESS)
+ throw System_Error("System_RNG failed to acquire crypto provider", ret);
+ }
+
+ ~System_RNG_Impl()
+ {
+ ::BCryptCloseAlgorithmProvider(m_prov, 0);
+ }
+
+ void randomize(uint8_t buf[], size_t len) override
+ {
+ NTSTATUS ret = ::BCryptGenRandom(m_prov, static_cast<PUCHAR>(buf), static_cast<ULONG>(len), 0);
+ if(ret != STATUS_SUCCESS)
+ throw System_Error("System_RNG call to BCryptGenRandom failed", ret);
+ }
+
+ void add_entropy(const uint8_t in[], size_t length) override
+ {
+ /*
+ There is a flag BCRYPT_RNG_USE_ENTROPY_IN_BUFFER to provide
+ entropy inputs, but it is ignored in Windows 8 and later.
+ */
+ }
+
+ bool is_seeded() const override { return true; }
+ bool accepts_input() const override { return false; }
+ void clear() override { /* not possible */ }
+ std::string name() const override { return "crypto_ng"; }
+ private:
+ BCRYPT_ALG_HANDLE m_prov;
+ };
+
+#elif defined(BOTAN_TARGET_OS_HAS_ARC4RANDOM)
+
+class System_RNG_Impl final : public RandomNumberGenerator
+ {
+ public:
+ // No constructor or destructor needed as no userland state maintained
+
+ void randomize(uint8_t buf[], size_t len) override
+ {
+ // macOS 10.15 arc4random crashes if called with buf == nullptr && len == 0
+ if(len > 0)
+ {
+ ::arc4random_buf(buf, len);
+ }
+ }
+
+ bool accepts_input() const override { return false; }
+ void add_entropy(const uint8_t[], size_t) override { /* ignored */ }
+ bool is_seeded() const override { return true; }
+ void clear() override { /* not possible */ }
+ std::string name() const override { return "arc4random"; }
+ };
+
+#elif defined(BOTAN_TARGET_OS_HAS_GETRANDOM)
+
+class System_RNG_Impl final : public RandomNumberGenerator
+ {
+ public:
+ // No constructor or destructor needed as no userland state maintained
+
+ void randomize(uint8_t buf[], size_t len) override
+ {
+ const unsigned int flags = 0;
+
+ while(len > 0)
+ {
+ const ssize_t got = ::getrandom(buf, len, flags);
+
+ if(got < 0)
+ {
+ if(errno == EINTR)
+ continue;
+ throw System_Error("System_RNG getrandom failed", errno);
+ }
+
+ buf += got;
+ len -= got;
+ }
+ }
+
+ bool accepts_input() const override { return false; }
+ void add_entropy(const uint8_t[], size_t) override { /* ignored */ }
+ bool is_seeded() const override { return true; }
+ void clear() override { /* not possible */ }
+ std::string name() const override { return "getrandom"; }
+ };
+
+
+#elif defined(BOTAN_TARGET_OS_HAS_DEV_RANDOM)
+
+// Read a random device
+
+class System_RNG_Impl final : public RandomNumberGenerator
+ {
+ public:
+ System_RNG_Impl()
+ {
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY);
+
+ if(m_fd >= 0)
+ {
+ m_writable = true;
+ }
+ else
+ {
+ /*
+ Cannot open in read-write mode. Fall back to read-only,
+ calls to add_entropy will fail, but randomize will work
+ */
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY);
+ m_writable = false;
+ }
+
+ if(m_fd < 0)
+ throw System_Error("System_RNG failed to open RNG device", errno);
+ }
+
+ ~System_RNG_Impl()
+ {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+
+ void randomize(uint8_t buf[], size_t len) override;
+ void add_entropy(const uint8_t in[], size_t length) override;
+ bool is_seeded() const override { return true; }
+ bool accepts_input() const override { return m_writable; }
+ void clear() override { /* not possible */ }
+ std::string name() const override { return BOTAN_SYSTEM_RNG_DEVICE; }
+ private:
+ int m_fd;
+ bool m_writable;
+ };
+
+void System_RNG_Impl::randomize(uint8_t buf[], size_t len)
+ {
+ while(len)
+ {
+ ssize_t got = ::read(m_fd, buf, len);
+
+ if(got < 0)
+ {
+ if(errno == EINTR)
+ continue;
+ throw System_Error("System_RNG read failed", errno);
+ }
+ if(got == 0)
+ throw System_Error("System_RNG EOF on device"); // ?!?
+
+ buf += got;
+ len -= got;
+ }
+ }
+
+void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len)
+ {
+ if(!m_writable)
+ return;
+
+ while(len)
+ {
+ ssize_t got = ::write(m_fd, input, len);
+
+ if(got < 0)
+ {
+ if(errno == EINTR)
+ continue;
+
+ /*
+ * This is seen on OS X CI, despite the fact that the man page
+ * for macOS urandom explicitly states that writing to it is
+ * supported, and write(2) does not document EPERM at all.
+ * But in any case EPERM seems indicative of a policy decision
+ * by the OS or sysadmin that additional entropy is not wanted
+ * in the system pool, so we accept that and return here,
+ * since there is no corrective action possible.
+ *
+ * In Linux EBADF or EPERM is returned if m_fd is not opened for
+ * writing.
+ */
+ if(errno == EPERM || errno == EBADF)
+ return;
+
+ // maybe just ignore any failure here and return?
+ throw System_Error("System_RNG write failed", errno);
+ }
+
+ input += got;
+ len -= got;
+ }
+ }
+
+#endif
+
+}
+
+RandomNumberGenerator& system_rng()
+ {
+ static System_RNG_Impl g_system_rng;
+ return g_system_rng;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h
new file mode 100644
index 0000000000..e0f0181ca1
--- /dev/null
+++ b/comm/third_party/botan/src/lib/rng/system_rng/system_rng.h
@@ -0,0 +1,43 @@
+/*
+* System RNG interface
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SYSTEM_RNG_H_
+#define BOTAN_SYSTEM_RNG_H_
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+/**
+* Return a shared reference to a global PRNG instance provided by the
+* operating system. For instance might be instantiated by /dev/urandom
+* or CryptGenRandom.
+*/
+BOTAN_PUBLIC_API(2,0) RandomNumberGenerator& system_rng();
+
+/*
+* Instantiable reference to the system RNG.
+*/
+class BOTAN_PUBLIC_API(2,0) System_RNG final : public RandomNumberGenerator
+ {
+ public:
+ std::string name() const override { return system_rng().name(); }
+
+ void randomize(uint8_t out[], size_t len) override { system_rng().randomize(out, len); }
+
+ void add_entropy(const uint8_t in[], size_t length) override { system_rng().add_entropy(in, length); }
+
+ bool is_seeded() const override { return system_rng().is_seeded(); }
+
+ bool accepts_input() const override { return system_rng().accepts_input(); }
+
+ void clear() override { system_rng().clear(); }
+ };
+
+}
+
+#endif