aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rng
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-01-01 21:20:55 +0000
committerlloyd <[email protected]>2014-01-01 21:20:55 +0000
commit197dc467dec28a04c3b2f30da7cef122dfbb13e9 (patch)
treecdbd3ddaec051c72f0a757db461973d90c37b97a /lib/rng
parent62faac373c07cfe10bc8c309e89ebdd30d8e5eaa (diff)
Shuffle things around. Add NIST X.509 test to build.
Diffstat (limited to 'lib/rng')
-rw-r--r--lib/rng/auto_rng/auto_rng.h41
-rw-r--r--lib/rng/auto_rng/info.txt8
-rw-r--r--lib/rng/hmac_rng/hmac_rng.cpp205
-rw-r--r--lib/rng/hmac_rng/hmac_rng.h57
-rw-r--r--lib/rng/hmac_rng/info.txt5
-rw-r--r--lib/rng/info.txt3
-rw-r--r--lib/rng/rng.cpp34
-rw-r--r--lib/rng/rng.h174
-rw-r--r--lib/rng/x931_rng/info.txt5
-rw-r--r--lib/rng/x931_rng/x931_rng.cpp146
-rw-r--r--lib/rng/x931_rng/x931_rng.h50
11 files changed, 728 insertions, 0 deletions
diff --git a/lib/rng/auto_rng/auto_rng.h b/lib/rng/auto_rng/auto_rng.h
new file mode 100644
index 000000000..13201f251
--- /dev/null
+++ b/lib/rng/auto_rng/auto_rng.h
@@ -0,0 +1,41 @@
+/*
+* Auto Seeded RNG
+* (C) 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_AUTO_SEEDING_RNG_H__
+#define BOTAN_AUTO_SEEDING_RNG_H__
+
+#include <botan/rng.h>
+#include <string>
+#include <memory>
+
+namespace Botan {
+
+class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte out[], size_t len)
+ { m_rng->randomize(out, len); }
+
+ bool is_seeded() const { return m_rng->is_seeded(); }
+
+ void clear() { m_rng->clear(); }
+
+ std::string name() const { return m_rng->name(); }
+
+ void reseed(size_t poll_bits = 256) { m_rng->reseed(poll_bits); }
+
+ void add_entropy(const byte in[], size_t len)
+ { m_rng->add_entropy(in, len); }
+
+ AutoSeeded_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
+ private:
+ std::unique_ptr<RandomNumberGenerator> m_rng;
+ };
+
+}
+
+#endif
diff --git a/lib/rng/auto_rng/info.txt b/lib/rng/auto_rng/info.txt
new file mode 100644
index 000000000..848c06ac3
--- /dev/null
+++ b/lib/rng/auto_rng/info.txt
@@ -0,0 +1,8 @@
+define AUTO_SEEDING_RNG 20131128
+
+<requires>
+hmac_rng
+hmac
+sha2_32
+sha2_64
+</requires>
diff --git a/lib/rng/hmac_rng/hmac_rng.cpp b/lib/rng/hmac_rng/hmac_rng.cpp
new file mode 100644
index 000000000..98ae6439e
--- /dev/null
+++ b/lib/rng/hmac_rng/hmac_rng.cpp
@@ -0,0 +1,205 @@
+/*
+* HMAC_RNG
+* (C) 2008-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/hmac_rng.h>
+#include <botan/libstate.h>
+#include <botan/get_byte.h>
+#include <botan/entropy_src.h>
+#include <botan/internal/xor_buf.h>
+#include <algorithm>
+#include <chrono>
+
+namespace Botan {
+
+namespace {
+
+void hmac_prf(MessageAuthenticationCode& prf,
+ secure_vector<byte>& K,
+ u32bit& counter,
+ const std::string& label)
+ {
+ typedef std::chrono::high_resolution_clock clock;
+
+ auto timestamp = clock::now().time_since_epoch().count();
+
+ prf.update(K);
+ prf.update(label);
+ prf.update_be(timestamp);
+ prf.update_be(counter);
+ prf.final(&K[0]);
+
+ ++counter;
+ }
+
+}
+
+/*
+* HMAC_RNG Constructor
+*/
+HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
+ MessageAuthenticationCode* prf) :
+ m_extractor(extractor), m_prf(prf)
+ {
+ if(!m_prf->valid_keylength(m_extractor->output_length()) ||
+ !m_extractor->valid_keylength(m_prf->output_length()))
+ throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
+ m_extractor->name() + " and " +
+ m_prf->name());
+
+ // First PRF inputs are all zero, as specified in section 2
+ m_K.resize(m_prf->output_length());
+
+ /*
+ Normally we want to feedback PRF outputs to the extractor function
+ to ensure a single bad poll does not reduce entropy. Thus in reseed
+ we'll want to invoke the PRF before we reset the PRF key, but until
+ the first reseed the PRF is unkeyed. Rather than trying to keep
+ track of this, just set the initial PRF key to constant zero.
+ Since all PRF inputs in the first reseed are constants, this
+ amounts to suffixing the seed in the first poll with a fixed
+ constant string.
+
+ The PRF key will not be used to generate outputs until after reseed
+ sets m_seeded to true.
+ */
+ secure_vector<byte> prf_key(m_extractor->output_length());
+ m_prf->set_key(prf_key);
+
+ /*
+ Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.
+
+ This will be used during the first extraction sequence; XTS values
+ after this one are generated using the PRF.
+
+ If I understand the E-t-E paper correctly (specifically Section 4),
+ using this fixed extractor key is safe to do.
+ */
+ m_extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
+ }
+
+/*
+* Generate a buffer of random bytes
+*/
+void HMAC_RNG::randomize(byte out[], size_t length)
+ {
+ if(!is_seeded())
+ {
+ reseed(256);
+ if(!is_seeded())
+ throw PRNG_Unseeded(name());
+ }
+
+ const size_t max_per_prf_iter = m_prf->output_length() / 2;
+
+ /*
+ HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
+ */
+ while(length)
+ {
+ hmac_prf(*m_prf, m_K, m_counter, "rng");
+
+ const size_t copied = std::min<size_t>(length, max_per_prf_iter);
+
+ copy_mem(out, &m_K[0], copied);
+ out += copied;
+ length -= copied;
+
+ m_output_since_reseed += copied;
+
+ if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
+ reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ }
+ }
+
+/*
+* Poll for entropy and reset the internal keys
+*/
+void HMAC_RNG::reseed(size_t poll_bits)
+ {
+ /*
+ Using the terminology of E-t-E, XTR is the MAC function (normally
+ HMAC) seeded with XTS (below) and we form SKM, the key material, by
+ polling as many sources as we think needed to reach our polling
+ goal. We then also include feedback of the current PRK so that
+ a bad poll doesn't wipe us out.
+ */
+
+ Entropy_Accumulator_BufferedComputation accum(*m_extractor, poll_bits);
+
+ global_state().poll_available_sources(accum);
+
+ /*
+ * It is necessary to feed forward poll data. Otherwise, a good poll
+ * (collecting a large amount of conditional entropy) followed by a
+ * bad one (collecting little) would be unsafe. Do this by
+ * generating new PRF outputs using the previous key and feeding
+ * them into the extractor function.
+ *
+ * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF
+ * output using the CTXinfo "reseed". Provide these values as input
+ * to the extractor function.
+ */
+ hmac_prf(*m_prf, m_K, m_counter, "rng");
+ m_extractor->update(m_K); // K is the CTXinfo=rng PRF output
+
+ hmac_prf(*m_prf, m_K, m_counter, "reseed");
+ m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output
+
+ /* Now derive the new PRK using everything that has been fed into
+ the extractor, and set the PRF key to that */
+ m_prf->set_key(m_extractor->final());
+
+ // Now generate a new PRF output to use as the XTS extractor salt
+ hmac_prf(*m_prf, m_K, m_counter, "xts");
+ m_extractor->set_key(m_K);
+
+ // Reset state
+ zeroise(m_K);
+ m_counter = 0;
+
+ m_collected_entropy_estimate =
+ std::min(m_collected_entropy_estimate + accum.bits_collected(),
+ m_extractor->output_length() * 8);
+
+ m_output_since_reseed = 0;
+ }
+
+bool HMAC_RNG::is_seeded() const
+ {
+ return (m_collected_entropy_estimate >= 256);
+ }
+
+/*
+* Add user-supplied entropy to the extractor input
+*/
+void HMAC_RNG::add_entropy(const byte input[], size_t length)
+ {
+ m_extractor->update(input, length);
+ reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void HMAC_RNG::clear()
+ {
+ m_collected_entropy_estimate = 0;
+ m_extractor->clear();
+ m_prf->clear();
+ zeroise(m_K);
+ m_counter = 0;
+ }
+
+/*
+* Return the name of this type
+*/
+std::string HMAC_RNG::name() const
+ {
+ return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")";
+ }
+
+}
diff --git a/lib/rng/hmac_rng/hmac_rng.h b/lib/rng/hmac_rng/hmac_rng.h
new file mode 100644
index 000000000..8fee5be5a
--- /dev/null
+++ b/lib/rng/hmac_rng/hmac_rng.h
@@ -0,0 +1,57 @@
+/*
+* HMAC RNG
+* (C) 2008,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_HMAC_RNG_H__
+#define BOTAN_HMAC_RNG_H__
+
+#include <botan/mac.h>
+#include <botan/rng.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* HMAC_RNG - based on the design described in "On Extract-then-Expand
+* Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk
+* (henceforce, 'E-t-E')
+*
+* However it actually can be parameterized with any two MAC functions,
+* not restricted to HMAC (this variation is also described in
+* Krawczyk's paper), for instance one could use HMAC(SHA-512) as the
+* extractor and CMAC(AES-256) as the PRF.
+*/
+class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte buf[], size_t len);
+ bool is_seeded() const;
+ void clear();
+ std::string name() const;
+
+ void reseed(size_t poll_bits);
+ void add_entropy(const byte[], size_t);
+
+ /**
+ * @param extractor a MAC used for extracting the entropy
+ * @param prf a MAC used as a PRF using HKDF construction
+ */
+ HMAC_RNG(MessageAuthenticationCode* extractor,
+ MessageAuthenticationCode* prf);
+ private:
+ std::unique_ptr<MessageAuthenticationCode> m_extractor;
+ std::unique_ptr<MessageAuthenticationCode> m_prf;
+
+ size_t m_collected_entropy_estimate = 0;
+ size_t m_output_since_reseed = 0;
+
+ secure_vector<byte> m_K;
+ u32bit m_counter = 0;
+ };
+
+}
+
+#endif
diff --git a/lib/rng/hmac_rng/info.txt b/lib/rng/hmac_rng/info.txt
new file mode 100644
index 000000000..36a8a7a34
--- /dev/null
+++ b/lib/rng/hmac_rng/info.txt
@@ -0,0 +1,5 @@
+define HMAC_RNG 20131128
+
+<requires>
+mac
+</requires>
diff --git a/lib/rng/info.txt b/lib/rng/info.txt
new file mode 100644
index 000000000..4c88ba382
--- /dev/null
+++ b/lib/rng/info.txt
@@ -0,0 +1,3 @@
+<requires>
+entropy
+</requires>
diff --git a/lib/rng/rng.cpp b/lib/rng/rng.cpp
new file mode 100644
index 000000000..12a6c163e
--- /dev/null
+++ b/lib/rng/rng.cpp
@@ -0,0 +1,34 @@
+/*
+* Random Number Generator Base
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/rng.h>
+#include <botan/hmac_rng.h>
+#include <botan/libstate.h>
+
+namespace Botan {
+
+RandomNumberGenerator* RandomNumberGenerator::make_rng()
+ {
+ return make_rng(global_state().algorithm_factory()).release();
+ }
+
+/*
+* Create and seed a new RNG object
+*/
+std::unique_ptr<RandomNumberGenerator> RandomNumberGenerator::make_rng(Algorithm_Factory& af)
+ {
+ std::unique_ptr<RandomNumberGenerator> rng(
+ new HMAC_RNG(af.make_mac("HMAC(SHA-512)"),
+ af.make_mac("HMAC(SHA-256)"))
+ );
+
+ rng->reseed(256);
+
+ return rng;
+ }
+
+}
diff --git a/lib/rng/rng.h b/lib/rng/rng.h
new file mode 100644
index 000000000..8664ccbf7
--- /dev/null
+++ b/lib/rng/rng.h
@@ -0,0 +1,174 @@
+/*
+* RandomNumberGenerator
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__
+#define BOTAN_RANDOM_NUMBER_GENERATOR_H__
+
+#include <botan/entropy_src.h>
+#include <botan/exceptn.h>
+#include <string>
+#include <memory>
+#include <mutex>
+
+namespace Botan {
+
+/**
+* This class represents a random number (RNG) generator object.
+*/
+class BOTAN_DLL RandomNumberGenerator
+ {
+ public:
+ /**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.8.0
+ */
+ static RandomNumberGenerator* make_rng();
+
+ /**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.11.5
+ */
+ static std::unique_ptr<RandomNumberGenerator> make_rng(class Algorithm_Factory& af);
+
+ /**
+ * Randomize a byte array.
+ * @param output the byte array to hold the random output.
+ * @param length the length of the byte array output.
+ */
+ virtual void randomize(byte output[], size_t length) = 0;
+
+ /**
+ * Return a random vector
+ * @param bytes number of bytes in the result
+ * @return randomized vector of length bytes
+ */
+ secure_vector<byte> random_vec(size_t bytes)
+ {
+ secure_vector<byte> output(bytes);
+ randomize(&output[0], output.size());
+ return output;
+ }
+
+ /**
+ * Return a random byte
+ * @return random byte
+ */
+ byte next_byte()
+ {
+ byte out;
+ this->randomize(&out, 1);
+ return out;
+ }
+
+ /**
+ * Check whether this RNG is seeded.
+ * @return true if this RNG was already seeded, false otherwise.
+ */
+ virtual bool is_seeded() const = 0;
+
+ /**
+ * Clear all internally held values of this RNG.
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Return the name of this object
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ * Seed this RNG using the entropy sources it contains.
+ * @param bits_to_collect is the number of bits of entropy to
+ attempt to gather from the entropy sources
+ */
+ virtual void reseed(size_t bits_to_collect) = 0;
+
+ /**
+ * Add entropy to this RNG.
+ * @param in a byte array containg the entropy to be added
+ * @param length the length of the byte array in
+ */
+ virtual void add_entropy(const byte in[], size_t length) = 0;
+
+ /*
+ * Never copy a RNG, create a new one
+ */
+ RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
+ RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
+
+ RandomNumberGenerator() {}
+ virtual ~RandomNumberGenerator() {}
+ };
+
+/**
+* Null/stub RNG - fails if you try to use it for anything
+*/
+class BOTAN_DLL Null_RNG : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte[], size_t) override { throw PRNG_Unseeded("Null_RNG"); }
+
+ void clear() override {}
+
+ std::string name() const override { return "Null_RNG"; }
+
+ void reseed(size_t) override {}
+ bool is_seeded() const override { return false; }
+ void add_entropy(const byte[], size_t) override {}
+ };
+
+/**
+* Wraps access to a RNG in a mutex
+*/
+class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte out[], size_t len)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_rng->randomize(out, len);
+ }
+
+ bool is_seeded() const
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_rng->is_seeded();
+ }
+
+ void clear()
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_rng->clear();
+ }
+
+ std::string name() const
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_rng->name();
+ }
+
+ void reseed(size_t poll_bits)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_rng->reseed(poll_bits);
+ }
+
+ void add_entropy(const byte in[], size_t len)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_rng->add_entropy(in, len);
+ }
+
+ Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
+ private:
+ mutable std::mutex m_mutex;
+ std::unique_ptr<RandomNumberGenerator> m_rng;
+ };
+
+}
+
+#endif
diff --git a/lib/rng/x931_rng/info.txt b/lib/rng/x931_rng/info.txt
new file mode 100644
index 000000000..beab0dbfd
--- /dev/null
+++ b/lib/rng/x931_rng/info.txt
@@ -0,0 +1,5 @@
+define X931_RNG 20131128
+
+<requires>
+block
+</requires>
diff --git a/lib/rng/x931_rng/x931_rng.cpp b/lib/rng/x931_rng/x931_rng.cpp
new file mode 100644
index 000000000..b36f87106
--- /dev/null
+++ b/lib/rng/x931_rng/x931_rng.cpp
@@ -0,0 +1,146 @@
+/*
+* ANSI X9.31 RNG
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/x931_rng.h>
+#include <botan/internal/xor_buf.h>
+#include <algorithm>
+
+namespace Botan {
+
+/*
+* Generate a buffer of random bytes
+*/
+void ANSI_X931_RNG::randomize(byte out[], size_t length)
+ {
+ if(!is_seeded())
+ throw PRNG_Unseeded(name());
+
+ while(length)
+ {
+ if(position == R.size())
+ update_buffer();
+
+ const size_t copied = std::min<size_t>(length, R.size() - position);
+
+ copy_mem(out, &R[position], copied);
+ out += copied;
+ length -= copied;
+ position += copied;
+ }
+ }
+
+/*
+* Refill the internal state
+*/
+void ANSI_X931_RNG::update_buffer()
+ {
+ const size_t BLOCK_SIZE = cipher->block_size();
+
+ secure_vector<byte> DT = prng->random_vec(BLOCK_SIZE);
+ cipher->encrypt(DT);
+
+ xor_buf(&R[0], &V[0], &DT[0], BLOCK_SIZE);
+ cipher->encrypt(R);
+
+ xor_buf(&V[0], &R[0], &DT[0], BLOCK_SIZE);
+ cipher->encrypt(V);
+
+ position = 0;
+ }
+
+/*
+* Reset V and the cipher key with new values
+*/
+void ANSI_X931_RNG::rekey()
+ {
+ const size_t BLOCK_SIZE = cipher->block_size();
+
+ if(prng->is_seeded())
+ {
+ cipher->set_key(prng->random_vec(cipher->maximum_keylength()));
+
+ if(V.size() != BLOCK_SIZE)
+ V.resize(BLOCK_SIZE);
+ prng->randomize(&V[0], V.size());
+
+ update_buffer();
+ }
+ }
+
+/*
+* Reseed the internal state
+*/
+void ANSI_X931_RNG::reseed(size_t poll_bits)
+ {
+ prng->reseed(poll_bits);
+ rekey();
+ }
+
+/*
+* Add some entropy to the underlying PRNG
+*/
+void ANSI_X931_RNG::add_entropy(const byte input[], size_t length)
+ {
+ prng->add_entropy(input, length);
+ rekey();
+ }
+
+/*
+* Check if the the PRNG is seeded
+*/
+bool ANSI_X931_RNG::is_seeded() const
+ {
+ return (V.size() > 0);
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void ANSI_X931_RNG::clear()
+ {
+ cipher->clear();
+ prng->clear();
+ zeroise(R);
+ V.clear();
+
+ position = 0;
+ }
+
+/*
+* Return the name of this type
+*/
+std::string ANSI_X931_RNG::name() const
+ {
+ return "X9.31(" + cipher->name() + ")";
+ }
+
+/*
+* ANSI X931 RNG Constructor
+*/
+ANSI_X931_RNG::ANSI_X931_RNG(BlockCipher* cipher_in,
+ RandomNumberGenerator* prng_in)
+ {
+ if(!prng_in || !cipher_in)
+ throw Invalid_Argument("ANSI_X931_RNG constructor: NULL arguments");
+
+ cipher = cipher_in;
+ prng = prng_in;
+
+ R.resize(cipher->block_size());
+ position = 0;
+ }
+
+/*
+* ANSI X931 RNG Destructor
+*/
+ANSI_X931_RNG::~ANSI_X931_RNG()
+ {
+ delete cipher;
+ delete prng;
+ }
+
+}
diff --git a/lib/rng/x931_rng/x931_rng.h b/lib/rng/x931_rng/x931_rng.h
new file mode 100644
index 000000000..8052cedc3
--- /dev/null
+++ b/lib/rng/x931_rng/x931_rng.h
@@ -0,0 +1,50 @@
+/*
+* ANSI X9.31 RNG
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ANSI_X931_RNG_H__
+#define BOTAN_ANSI_X931_RNG_H__
+
+#include <botan/rng.h>
+#include <botan/block_cipher.h>
+
+namespace Botan {
+
+/**
+* ANSI X9.31 RNG
+*/
+class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
+ {
+ public:
+ void randomize(byte[], size_t);
+ bool is_seeded() const;
+ void clear();
+ std::string name() const;
+
+ void reseed(size_t poll_bits);
+ void add_entropy(const byte[], size_t);
+
+ /**
+ * @param cipher the block cipher to use in this PRNG
+ * @param rng the underlying PRNG for generating inputs
+ * (eg, an HMAC_RNG)
+ */
+ ANSI_X931_RNG(BlockCipher* cipher,
+ RandomNumberGenerator* rng);
+ ~ANSI_X931_RNG();
+ private:
+ void rekey();
+ void update_buffer();
+
+ BlockCipher* cipher;
+ RandomNumberGenerator* prng;
+ secure_vector<byte> V, R;
+ size_t position;
+ };
+
+}
+
+#endif