diff options
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/rng')
18 files changed, 1621 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.cpp new file mode 100644 index 0000000000..ec439e7cfb --- /dev/null +++ b/src/libs/3rdparty/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 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 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) + { + 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/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h new file mode 100644 index 0000000000..866c56e12f --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/auto_rng.h @@ -0,0 +1,96 @@ +/* +* 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; + + /** + * 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); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @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); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @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); + + /** + * Uses the BOTAN_AUTO_RNG_DRBG RNG to gather seed material. + * + * @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/src/libs/3rdparty/botan/src/lib/rng/auto_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/auto_rng/info.txt new file mode 100644 index 0000000000..f1adcc8001 --- /dev/null +++ b/src/libs/3rdparty/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/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp new file mode 100644 index 0000000000..a01b761d99 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -0,0 +1,184 @@ +/* +* 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 { + +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) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for 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) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for 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) + { + BOTAN_ASSERT_NONNULL(m_mac); + + if(m_max_number_of_bytes_per_request == 0 || m_max_number_of_bytes_per_request > 64 * 1024) + { + throw Invalid_Argument("Invalid value for 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) + { + BOTAN_ASSERT_NONNULL(m_mac); + clear(); + } + +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<uint8_t>(m_mac->output_length(), 0x00)); + } + +std::string HMAC_DRBG::name() const + { + return "HMAC_DRBG(" + m_mac->name() + ")"; + } + +void HMAC_DRBG::randomize(uint8_t output[], size_t output_len) + { + randomize_with_input(output, output_len, nullptr, 0); + } + +/* +* HMAC_DRBG generation +* See NIST SP800-90A section 10.1.2.5 +*/ +void HMAC_DRBG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + while(output_len > 0) + { + size_t this_req = std::min(m_max_number_of_bytes_per_request, output_len); + output_len -= this_req; + + 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; + this_req -= 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) + { + m_mac->update(m_V); + m_mac->update(0x00); + m_mac->update(input, input_len); + m_mac->set_key(m_mac->final()); + + 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->set_key(m_mac->final()); + + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + } + } + +void HMAC_DRBG::add_entropy(const uint8_t input[], size_t input_len) + { + update(input, input_len); + + if(8*input_len >= security_level()) + { + reset_reseed_counter(); + } + } + +size_t HMAC_DRBG::security_level() const + { + // 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(m_mac->output_length() < 32) + { + return (m_mac->output_length() - 4) * 8; + } + else + { + return 32 * 8; + } + } +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h new file mode 100644 index 0000000000..edf38b6842 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -0,0 +1,159 @@ +/* +* 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); + + /** + * 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 + * @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. + * @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. + * @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); + + /** + * Constructor taking a string for the hash + */ + explicit 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) + { + clear(); + } + + std::string name() const override; + + void clear() override; + + void randomize(uint8_t output[], size_t output_len) override; + + void randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) override; + + void add_entropy(const uint8_t input[], size_t input_len) 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); + + std::unique_ptr<MessageAuthenticationCode> m_mac; + secure_vector<uint8_t> m_V; + const size_t m_max_number_of_bytes_per_request; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/info.txt b/src/libs/3rdparty/botan/src/lib/rng/hmac_drbg/info.txt new file mode 100644 index 0000000000..a8922bdf0e --- /dev/null +++ b/src/libs/3rdparty/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/src/libs/3rdparty/botan/src/lib/rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/info.txt new file mode 100644 index 0000000000..4c88ba3826 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/info.txt @@ -0,0 +1,3 @@ +<requires> +entropy +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt new file mode 100644 index 0000000000..0d0fc42a42 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/info.txt @@ -0,0 +1,13 @@ +<defines> +RDRAND_RNG -> 20160619 +</defines> + +need_isa rdrand + +<cc> +gcc +clang +icc +msvc +</cc> + diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp new file mode 100644 index 0000000000..c365a5f760 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -0,0 +1,83 @@ +/* +* RDRAND RNG +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/rdrand_rng.h> +#include <botan/loadstor.h> +#include <botan/cpuid.h> + +#if !defined(BOTAN_USE_GCC_INLINE_ASM) + #include <immintrin.h> +#endif + +namespace Botan { + +RDRAND_RNG::RDRAND_RNG() + { + if(!CPUID::has_rdrand()) + throw Exception("Current CPU does not support RDRAND instruction"); + } + +//static +uint32_t RDRAND_RNG::rdrand() + { + for(;;) + { + bool ok = false; + uint32_t r = rdrand_status(ok); + if(ok) + return r; + } + } + +//static +BOTAN_FUNC_ISA("rdrnd") +uint32_t RDRAND_RNG::rdrand_status(bool& ok) + { + ok = false; + uint32_t r = 0; + + for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i) + { +#if defined(BOTAN_USE_GCC_INLINE_ASM) + int cf = 0; + + // Encoding of rdrand %eax + asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" : + "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc"); +#else + int cf = _rdrand32_step(&r); +#endif + if(1 == cf) + { + ok = true; + break; + } + } + + return r; + } + +void RDRAND_RNG::randomize(uint8_t out[], size_t out_len) + { + while(out_len >= 4) + { + uint32_t r = RDRAND_RNG::rdrand(); + + store_le(r, out); + out += 4; + out_len -= 4; + } + + if(out_len) // between 1 and 3 trailing bytes + { + uint32_t r = RDRAND_RNG::rdrand(); + for(size_t i = 0; i != out_len; ++i) + out[i] = get_byte(i, r); + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h new file mode 100644 index 0000000000..377de419f7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rdrand_rng/rdrand_rng.h @@ -0,0 +1,61 @@ +/* +* RDRAND RNG +* (C) 2016 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: + /** + * 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 rdrand_status(bool& ok); + + /* + * Calls RDRAND until it succeeds, this could hypothetically + * loop forever on broken hardware. + */ + static uint32_t rdrand(); + + /** + * Constructor will throw if CPU does not have RDRAND bit set + */ + RDRAND_RNG(); + + /** + * 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; } + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/rng/rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/rng.cpp new file mode 100644 index 0000000000..2cf3b7b81e --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rng.cpp @@ -0,0 +1,74 @@ +/* +* (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) + { + /* + 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); + + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + +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) + { + return srcs.poll(*this, poll_bits, poll_timeout); + } + +void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) + { + 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 Exception("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 Exception("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); + } +#endif + +#endif + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/rng.h b/src/libs/3rdparty/botan/src/lib/rng/rng.h new file mode 100644 index 0000000000..f6fa80df06 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/rng.h @@ -0,0 +1,264 @@ +/* +* 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 <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; + + /** + * 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) + { + 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(bytes); + this->randomize(output.data(), output.size()); + return output; + } + + /** + * 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 has no members but exists to tag hardware RNG types +* (PKCS11_RNG, TPM_RNG, RDRAND_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; } + + 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 +*/ +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 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)") Serialized_RNG(); + + 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/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt new file mode 100644 index 0000000000..edc2d91694 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/info.txt @@ -0,0 +1,3 @@ +<defines> +STATEFUL_RNG -> 20160819 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.cpp new file mode 100644 index 0000000000..dec7917938 --- /dev/null +++ b/src/libs/3rdparty/botan/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 uint8_t input[], size_t len) + { + add_entropy(input, len); + + if(8*len >= security_level()) + { + reset_reseed_counter(); + } + } + +void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len) + { + uint8_t additional_input[24] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_high_resolution_clock(), 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()) + { + reset_reseed_counter(); + } + + 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()) + { + reset_reseed_counter(); + } + } + +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/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h new file mode 100644 index 0000000000..18697ae231 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/stateful_rng/stateful_rng.h @@ -0,0 +1,151 @@ +/* +* (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_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; + + /** + * 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(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; + + protected: + void reseed_check(); + + /** + * Called by a subclass to notify that a reseed has been + * successfully performed. + */ + void reset_reseed_counter() { m_reseed_counter = 1; } + + 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; + 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/src/libs/3rdparty/botan/src/lib/rng/system_rng/info.txt b/src/libs/3rdparty/botan/src/lib/rng/system_rng/info.txt new file mode 100644 index 0000000000..da4fce4e36 --- /dev/null +++ b/src/libs/3rdparty/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.lib +</libs> + +<requires> +rtlgenrandom?dyn_load +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp new file mode 100644 index 0000000000..c3b37ea9cc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.cpp @@ -0,0 +1,231 @@ +/* +* 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_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, len) == TRUE; + if(!success) + throw Exception("RtlGenRandom failed"); + } + + 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 "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 Exception("System_RNG failed to acquire crypto provider"); + } + + ~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 Exception("System_RNG call to BCryptGenRandom failed"); + } + + 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; } + void clear() override { /* not possible */ } + std::string name() const override { return "crypto_ng"; } + private: + BCRYPT_ALG_HANDLE m_handle; + }; + +#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 + { + ::arc4random_buf(buf, len); + } + + 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_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); + + /* + Cannot open in read-write mode. Fall back to read-only, + calls to add_entropy will fail, but randomize will work + */ + if(m_fd < 0) + m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY); + + if(m_fd < 0) + throw Exception("System_RNG failed to open RNG device"); + } + + ~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; } + void clear() override { /* not possible */ } + std::string name() const override { return BOTAN_SYSTEM_RNG_DEVICE; } + private: + int m_fd; + }; + +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 Exception("System_RNG read failed error " + std::to_string(errno)); + } + if(got == 0) + throw Exception("System_RNG EOF on device"); // ?!? + + buf += got; + len -= got; + } + } + +void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) + { + 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 Darwin 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 Exception("System_RNG write failed error " + std::to_string(errno)); + } + + input += got; + len -= got; + } + } + +#endif + +} + +RandomNumberGenerator& system_rng() + { + static System_RNG_Impl g_system_rng; + return g_system_rng; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h new file mode 100644 index 0000000000..4e3beaf9fb --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/rng/system_rng/system_rng.h @@ -0,0 +1,41 @@ +/* +* 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(); } + + void clear() override { system_rng().clear(); } + }; + +} + +#endif |