From 7edeec69f09fbed01881e93b0f45dbb038bfac73 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Mon, 31 Jul 2017 15:12:39 -0400 Subject: Add ChaCha_RNG --- src/lib/rng/chacha_rng/chacha_rng.cpp | 101 +++++++++++++++++++++++++++ src/lib/rng/chacha_rng/chacha_rng.h | 127 ++++++++++++++++++++++++++++++++++ src/lib/rng/chacha_rng/info.txt | 10 +++ 3 files changed, 238 insertions(+) create mode 100644 src/lib/rng/chacha_rng/chacha_rng.cpp create mode 100644 src/lib/rng/chacha_rng/chacha_rng.h create mode 100644 src/lib/rng/chacha_rng/info.txt (limited to 'src/lib/rng') diff --git a/src/lib/rng/chacha_rng/chacha_rng.cpp b/src/lib/rng/chacha_rng/chacha_rng.cpp new file mode 100644 index 000000000..86c71f9fe --- /dev/null +++ b/src/lib/rng/chacha_rng/chacha_rng.cpp @@ -0,0 +1,101 @@ +/* +* ChaCha_RNG +* (C) 2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include + +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& 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() + { + Stateful_RNG::clear(); + + m_hmac->set_key(std::vector(m_hmac->output_length(), 0x00)); + m_chacha->set_key(m_hmac->final()); + } + +void ChaCha_RNG::randomize(uint8_t output[], size_t output_len) + { + randomize_with_input(output, output_len, nullptr, 0); + } + +void ChaCha_RNG::randomize_with_input(uint8_t output[], size_t output_len, + const uint8_t input[], size_t input_len) + { + add_entropy(input, input_len); + reseed_check(); + + clear_mem(output, output_len); + m_chacha->cipher1(output, output_len); + } + +void ChaCha_RNG::add_entropy(const uint8_t input[], size_t input_len) + { + if(input_len > 0) + { + m_hmac->update(input, input_len); + m_chacha->set_key(m_hmac->final()); + + secure_vector mac_key(m_hmac->output_length()); + m_chacha->cipher1(mac_key.data(), mac_key.size()); + m_hmac->set_key(mac_key); + + if(8*input_len >= security_level()) + { + m_reseed_counter = 1; + } + } + } + +size_t ChaCha_RNG::security_level() const + { + return 256; + } + +} diff --git a/src/lib/rng/chacha_rng/chacha_rng.h b/src/lib/rng/chacha_rng/chacha_rng.h new file mode 100644 index 000000000..b6a763f62 --- /dev/null +++ b/src/lib/rng/chacha_rng/chacha_rng.h @@ -0,0 +1,127 @@ +/* +* 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 +#include +#include + +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_DLL 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& 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"; } + + 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; + + private: + void update(const uint8_t input[], size_t input_len); + + std::unique_ptr m_hmac; + std::unique_ptr m_chacha; + }; + +} + +#endif diff --git a/src/lib/rng/chacha_rng/info.txt b/src/lib/rng/chacha_rng/info.txt new file mode 100644 index 000000000..3f51bf4d0 --- /dev/null +++ b/src/lib/rng/chacha_rng/info.txt @@ -0,0 +1,10 @@ + +CHACHA_RNG -> 20170728 + + + +hmac +sha2_32 +chacha +stateful_rng + -- cgit v1.2.3