aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-07-31 15:12:39 -0400
committerJack Lloyd <[email protected]>2017-08-03 10:36:42 -0400
commit7edeec69f09fbed01881e93b0f45dbb038bfac73 (patch)
tree0ea798a7c1cc708b167d899eed73bedb927ec247
parent62da578b1a166fa7885940457ad186cd0c948bab (diff)
Add ChaCha_RNG
-rw-r--r--doc/manual/rng.rst13
-rw-r--r--src/build-data/policy/bsi.txt3
-rw-r--r--src/build-data/policy/nist.txt3
-rw-r--r--src/cli/speed.cpp63
-rw-r--r--src/lib/rng/chacha_rng/chacha_rng.cpp101
-rw-r--r--src/lib/rng/chacha_rng/chacha_rng.h127
-rw-r--r--src/lib/rng/chacha_rng/info.txt10
-rw-r--r--src/tests/data/rng/chacha_rng.vec129
-rw-r--r--src/tests/test_rng.cpp50
9 files changed, 451 insertions, 48 deletions
diff --git a/doc/manual/rng.rst b/doc/manual/rng.rst
index 7d586e743..592f319fa 100644
--- a/doc/manual/rng.rst
+++ b/doc/manual/rng.rst
@@ -78,6 +78,19 @@ initial seed is generated either by the system PRNG (if available) or
a default set of entropy sources. These are also used for periodic
reseeding of the RNG state.
+ChaCha_RNG
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is a very fast userspace PRNG based on ChaCha20 and HMAC(SHA-256). The key
+for ChaCha is derived by hashing entropy inputs with HMAC. Then the ChaCha
+keystream generator is run, first to generate the new HMAC key (used for any
+future entropy additions), then the desired RNG outputs.
+
+This RNG composes two primitives thought to be secure (ChaCha and HMAC) in a
+simple and well studied way (the extract-then-expand paradigm), but is still an
+ad-hoc and non-standard construction. It is included because it is roughly 20x
+faster then HMAC_DRBG, and certain applications need access to a very fast RNG.
+
TPM_RNG
^^^^^^^^^^^^^^^^^
diff --git a/src/build-data/policy/bsi.txt b/src/build-data/policy/bsi.txt
index c4b9e4769..bc2e7d7f3 100644
--- a/src/build-data/policy/bsi.txt
+++ b/src/build-data/policy/bsi.txt
@@ -155,6 +155,9 @@ tiger
whirlpool
keccak
+# rng
+chacha_rng
+
# mac
cbc_mac
poly1305
diff --git a/src/build-data/policy/nist.txt b/src/build-data/policy/nist.txt
index fe5183f15..4fafe7149 100644
--- a/src/build-data/policy/nist.txt
+++ b/src/build-data/policy/nist.txt
@@ -156,6 +156,9 @@ sm3
tiger
whirlpool
+# rng
+chacha_rng
+
# mac
cbc_mac
poly1305
diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp
index 7f25496e4..7705f89c1 100644
--- a/src/cli/speed.cpp
+++ b/src/cli/speed.cpp
@@ -44,14 +44,14 @@
#include <botan/hmac_drbg.h>
#endif
-#if defined(BOTAN_HAS_HMAC_RNG)
- #include <botan/hmac_rng.h>
-#endif
-
#if defined(BOTAN_HAS_RDRAND_RNG)
#include <botan/rdrand_rng.h>
#endif
+#if defined(BOTAN_HAS_CHACHA_RNG)
+ #include <botan/chacha_rng.h>
+#endif
+
#if defined(BOTAN_HAS_FPE_FE1)
#include <botan/fpe_fe1.h>
#endif
@@ -119,9 +119,8 @@
#include <botan/sm2.h>
#endif
-#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA)
+#if defined(BOTAN_HAS_NEWHOPE)
#include <botan/newhope.h>
- #include <botan/chacha.h>
#endif
namespace Botan_CLI {
@@ -793,7 +792,7 @@ class Speed final : public Command
bench_xmss(provider, msec);
}
#endif
-#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA)
+#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA_RNG)
else if(algo == "NEWHOPE")
{
bench_newhope(provider, msec);
@@ -838,7 +837,7 @@ class Speed final : public Command
{
#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
Botan::AutoSeeded_RNG auto_rng;
- bench_rng(auto_rng, "AutoSeeded_RNG (periodic reseed)", msec, buf_sizes);
+ bench_rng(auto_rng, "AutoSeeded_RNG (with reseed)", msec, buf_sizes);
#endif
#if defined(BOTAN_HAS_SYSTEM_RNG)
@@ -860,6 +859,13 @@ class Speed final : public Command
bench_rng(hmac_drbg, hmac_drbg.name(), msec, buf_sizes);
}
#endif
+
+#if defined(BOTAN_HAS_CHACHA_RNG)
+ // Provide a dummy seed
+ Botan::ChaCha_RNG chacha_rng(Botan::secure_vector<uint8_t>(32));
+ bench_rng(chacha_rng, "ChaCha_RNG", msec, buf_sizes);
+#endif
+
}
#if defined(BOTAN_HAS_SIMD_32) && defined(INCLUDE_SIMD_PERF)
else if(algo == "simd")
@@ -1965,7 +1971,7 @@ class Speed final : public Command
#endif
-#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA)
+#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA_RNG)
void bench_newhope(const std::string& /*provider*/,
std::chrono::milliseconds msec)
{
@@ -1975,44 +1981,7 @@ class Speed final : public Command
Timer shareda_timer(nm, "", "shareda");
Timer sharedb_timer(nm, "", "sharedb");
- class ChaCha20_RNG : public Botan::RandomNumberGenerator
- {
- public:
- std::string name() const override
- {
- return "ChaCha20_RNG";
- }
- void clear() override
- {
- /* ignored */
- }
-
- void randomize(uint8_t out[], size_t len) override
- {
- Botan::clear_mem(out, len);
- m_chacha.cipher1(out, len);
- }
-
- bool is_seeded() const override
- {
- return true;
- }
-
- void add_entropy(const uint8_t[], size_t) override
- {
- /* ignored */
- }
-
- ChaCha20_RNG(const Botan::secure_vector<uint8_t>& seed)
- {
- m_chacha.set_key(seed);
- }
-
- private:
- Botan::ChaCha m_chacha;
- };
-
- ChaCha20_RNG nh_rng(rng().random_vec(32));
+ Botan::ChaCha_RNG nh_rng;
while(sharedb_timer.under(msec))
{
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 <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()
+ {
+ Stateful_RNG::clear();
+
+ m_hmac->set_key(std::vector<uint8_t>(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<uint8_t> 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 <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_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<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"; }
+
+ 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<MessageAuthenticationCode> m_hmac;
+ std::unique_ptr<StreamCipher> 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 @@
+<defines>
+CHACHA_RNG -> 20170728
+</defines>
+
+<requires>
+hmac
+sha2_32
+chacha
+stateful_rng
+</requires>
diff --git a/src/tests/data/rng/chacha_rng.vec b/src/tests/data/rng/chacha_rng.vec
new file mode 100644
index 000000000..efcab692a
--- /dev/null
+++ b/src/tests/data/rng/chacha_rng.vec
@@ -0,0 +1,129 @@
+[ChaCha_RNG]
+
+# These vectors were generated by a simple implementation of the RNG
+# written in Go
+
+EntropyInput = 0000000000000000000000000000000000000000000000000000000000000000
+EntropyInputReseed = 0000000000000000000000000000000000000000000000000000000000000000
+Out = a84e2a6af98d0a2601ffd05c994de713fa8da43b6f04b3c48c28b0b1b6c9c813726b1d536da5b8b359176c646a7156db35420d5ccd1cea945b246f25edf43b38
+
+EntropyInput = 38002f1ebfac64151ec02c602921ace0769a15b6f6f922b30b2743006269f935
+EntropyInputReseed = 2ecc6e719637e6ff5006e3691bbac01a83a2e4f0e407800abcc7063cd6bb47dc
+AdditionalInput1 = 37864bb3f4c5bf11cfb534b36444ea1c
+AdditionalInput2 = 9dca561150a4d622d50269d2aad18661
+Out = ed4901a43569b58c216e32e74d8b14769e1b101f6dd5d524032253fda7d8b4757ce4e7d4fe4d9e3b6c3e937140f930ba9e311b38160d1332457ecd01fd2c67df
+
+EntropyInput = 44c52257803c224984f23ffa9417ebb186309634b0fd948a9fa069d233cdfd59
+EntropyInputReseed = 99aa36ca2148b390fd5bd4a6bde52d1a0502ee2633eeb1ea0dd1225dc623e6db
+AdditionalInput1 = a34c8be4076e135b07150a28516a2c3a
+AdditionalInput2 = 6c4d44cbed39c2bf09267232e5f989c6
+Out = 780f8a99d6719a656972df37000fc5ed0c514c29b1170ec55a2e8de76e0194879d80d4a3dace5bc31d7d011c8fc17e744df7c4741410704fe7708b5ea640b800
+
+EntropyInput = bdceae46180d07f7a581c94b0d91d85b976ecd65091c9b17bbb6486b4a293351
+EntropyInputReseed = 15bc3cfbafe7442936bb780c98b3a12d42b90976d6c8c575e8b2612697dd4d59
+AdditionalInput1 = 3d99f5d6d3b4d9b98ff4688aeeb545ba
+AdditionalInput2 = 058a43ed9d1852de48910d5ec0f2da64
+Out = 7b76eaae8b7ae31ac7fc4067a0b2b7e86eecfd951ce5e9e13a237a267a1db96bc247cfef9b233964508b302d0d325e5f620b9e7c08f6aa4bc0e5c5d69022220b
+
+EntropyInput = 0a4fb07966b36e583659edc71b61370f8d827b20d4de1bb0630b67d8d87b6d11
+EntropyInputReseed = 08bf1846a3c91d5a28f57344e9a5c3b11882659f4d20b2c13bc9e96a50c03c29
+AdditionalInput1 = 7e841fd11444f7ad7ee60953ff207b7e
+AdditionalInput2 = 420a562bebb4872d51a8b0e342197894
+Out = 6437a0f47661b11f340796bb78b5016a61a8b2795fea0e1a669a1fb6a02b5e5225e83df280243d7d5f54727d56a55a275d9ed5939bc250919a396916cef8e0b5
+
+EntropyInput = 0c04f83e4bdbd506738614e6b024060f511b8c9cfa5392d82e00447537191cc7
+EntropyInputReseed = b72ca03d42083f46cce8d6597185a9145fe15689edda6cda567363464c643358
+AdditionalInput1 = e4f77d67a03569338078b59a89dae593
+AdditionalInput2 = e3888f6f82a5b2ed3f12fe1e53c7386c
+Out = e6b8b885a857e98e0def1126dfaaa654f34ec32d9c7417c81aaf8a9aa6213e4cbf8962147155146e6ee49e3130f0b5cc66e7699661f9150ed380b8fe1978575a
+
+EntropyInput = d3fbbc4611908fa8d880be5dccdad79409742a1161345a6ddf553278c58c4a6c
+EntropyInputReseed = 34c397ce79b45c4605aad652f5e6fe90166dd8f2a0e4698bf39162e2d632489e
+AdditionalInput1 = 2d51b98143561b70cdc15fcc5b56a222
+AdditionalInput2 = 39e427807e0d2fea0e9ef6a71d1b3ca3
+Out = 81cf95a0030f00aae715f2fd37d7691fe05ee435530abd8c43f89e113c2ad306c596451047b14127f950c42af5640ca18d24a898c0bd6172d708d3750c947e5b
+
+EntropyInput = fb8a522fb21b923879460acc2ea2de865f46faf2ac12c9579a9dc22f5d268a3e
+EntropyInputReseed = 8747be06c76a504fe7c9d23cc2d6837dd519d54b123b7f5fa4dcbf3d2331da03
+AdditionalInput1 = 6856d58701a2beda014068818db45780
+AdditionalInput2 = 4642017cd6e61cf6764288af3c70c5ee
+Out = 610ff2f79cf09c7ea66207957b77574a320c91a26719e431121cd4d93b472f2021b7461eac8fd6cf917e4da37a45e728b488f723ef393d15de51bbd1ca908c9a
+
+EntropyInput = 772e616eb2b876a5e3a4cb148dd88695d0419957b1767b004a5eaf4c4927f3b4
+EntropyInputReseed = ecc4a344d2c4256d81b382293f71cf12aab1330f1088cfa61fa9ec235f818900
+AdditionalInput1 = 2133d928ee950dce00f190c187f9c1dd
+AdditionalInput2 = 49153c0dfbdecc902e24ba511ba3d22d
+Out = 38372a6f65fcfddc510a99f2d51c43702f796fa4a1dab0b2f0a0cb82436d70efe10253ff6e38c8dea3c38ecc08d197b020d7ac57fc12c7150b65a783536e5014
+
+EntropyInput = 946a5dd8c437c233efb44ea327eac846741ffb487ac9bcfc49468d69c26524d4
+EntropyInputReseed = 820b7f1cbe9730c378740eaf03cefa535fe9071cb3acac10bb7ec1bcef042346
+AdditionalInput1 = 2c2e72765402e28679caca88aea6a39e
+AdditionalInput2 = 4a20e2ff0684cc93861240dfe9df2e38
+Out = 05e6bd717775eea8ba4871da85786df45183c2f1957d2e36a8a2230ab53778e94cde92edb86646be2d600a891a12715727037663b53bd38802b5e9408385cb8d
+
+EntropyInput = 4ebec81abc28a39f683eb9137065bec349c9616178993dbe987b70ce1015a134
+EntropyInputReseed = f2422607b9c266408eb74c8ad21ac3be7d3d6e2ef498cedd63e30ba933efdd9e
+AdditionalInput1 = a822f49a68f5c98ab3afd1e7b27a9823
+AdditionalInput2 = d28a7dd06e69845c0dd8267621b5c867
+Out = 472aab0c6a53de0a4b7ce68720d7ef2766b7fe902633e09bb7cb4b056fbf6e2f251dd9486a0701fc9452f5dd2ffeb17eec04461361dfb5b0ae7ed919f0c177e8
+
+EntropyInput = bac6fc3d796008ea765028652fbe516818d43f7935f63511842520441a3d9aac
+EntropyInputReseed = 9834830402d7d087841e624b54f936d2cc554c3b77f12fefcaef492eed243d38
+AdditionalInput1 = c752b06e72d8f650e11ef9d556f613a4
+AdditionalInput2 = b84347008e613050c864d2596250f5d4
+Out = d9693147b1fcb434b68ca87bfd4b4791ac09dfc8a87448910157a1aa626f274b8aef568292a1c01982895c0310bd4597d2c5a6b1706116d7270866edc040d4d6
+
+EntropyInput = a01393aa35eeb3522dba2dcbaca4c28f1de3fac2066ea00a37f34142e1993592
+EntropyInputReseed = d2aca9b92f4483900da6ae2be81d8bd2ac2a2000016db48e5894acba30ee3dd3
+AdditionalInput1 = 42025c459f59e5f9847efc6cc4da1db8
+AdditionalInput2 = 7ebf89dcf9b491230edb26da11985137
+Out = f91d97378ebd55c25f527c65da5138771245a38867ab105117cadf2291509e5ffbd3fdf36505e2fe78300106e5febbaa4b08b4d98ed693dbcbc496048aff6d68
+
+EntropyInput = b2f2dd9263b1c1b4164c9f4ed4bea85c0397423c52efab1ebc84532df90b5f38
+EntropyInputReseed = 95e073c4a143b680f144782fddf621944b7fe1a9e15191256d6467596cc7847b
+AdditionalInput1 = 53d2f2101fd5b09a602f07bf2a2b04a2
+AdditionalInput2 = d52f100278121939d70f460a21dc218f
+Out = 92f3bf77ef6e6ca68bfda6581d791d059cc9d926df5356f032a96894bb9e3d37e82d40ac619bdce9f61532e878d5ef09e872b3cb9532c3d28792ea028f3a3a52
+
+EntropyInput = ea3dfed2728c8818c62b2901b993bb64aa246f324f0bb003cad7d3ebcf8ad3e3
+EntropyInputReseed = fb55d34c9ca100c4b5ab810953fe382beb639f233299beef53f0ba8edf24302d
+AdditionalInput1 = 465975974ca156cb55a127c393ae65ef
+AdditionalInput2 = 8fbd33f59b305e9991ae1ef5373395ca
+Out = 952770a8623fe7ffd9c3abbfcea3e1c43510e992e219aa0b087d3408112a521ecf3663c8cd60938b981c7568ad9000b07f895e7e197ab1d44f9a316c33e1d2dd
+
+EntropyInput = f38a98047fe48acfd2ee3da79263912cca4b9852e686bda3807045d3590eaaa2
+EntropyInputReseed = d87fd98d35218eaeec667e0c79f77a5b5f38daed8cbbdde4468b71204631a5b3
+AdditionalInput1 = b938b402dc3787d3330f0d961666ff4e
+AdditionalInput2 = a05d6789ac19c823dae0f53bb29fd39b
+Out = d7b5efc7f42d66d19e64c14eeb38d843b775bd7d836a12d8c2bef75623dfe3645cc0f2230b35c4ca708777681d062513847973d4547c8f3e5d41c7a60678995b
+
+EntropyInput = 11498ada4e77a9f6f9a185a42de81ec202a6246f6855d7eb9751185f338eafc0
+EntropyInputReseed = 772565fea0634216ee2a12ccc3ba87e334d14d9769ea0a2f4548154e1fc677c1
+AdditionalInput1 = 5c053b8a304fafac47faaa9eec3cd29d
+AdditionalInput2 = 14b24bee4e3104c917c8572dd44a3b46
+Out = 4a8d639007c14d3a7c3be860e833fae793560cbb48a47780c26969d9e7979c9f9e684c5d0fe6851e1434d7ed53c53e96e148557067a49b0b97e64e6418c6185c
+
+EntropyInput = 2d00c48b41cee9286e34b8bf916f91de9dc2f1ec9c0c53b4c663eb3f05410f4e
+EntropyInputReseed = b2703d38b570d83e8decc5981e057dc7dda6d88c5719df1bca7ef6bd54385a89
+AdditionalInput1 = ca8ffce1a2409694859347760c9cb9ff
+AdditionalInput2 = 31d0e14249c8ae9b356158b43fef10b7
+Out = fbd40489e7245f230649db916311829f687d92d387e5b01826bc365692af0c7f249c0b04db81620dabc577794a1ae054ab24d0b2b8e64936e6c29ea134672ffb
+
+EntropyInput = 7fa36f65c91f4487bb7a765283746ef8e6d43d32f74121ee3c57c5e8e23b771d
+EntropyInputReseed = c53787ac53e5eedbba4a813fd1c218d90a8f69f49c6fcc19d079e0570247e13d
+AdditionalInput1 = 629657f04b2e4b2d86e3fbaff4698bfb
+AdditionalInput2 = 190cd249e568096e962d8ff32b22c0de
+Out = 91311f7f36c695aa13dd87f7c9a7209f062522e27cb04af88177e22b8e3728d88d395edd803c80f2d02cf95a25aceac7708f2c2d5b1490b2af65a26e54e85765
+
+EntropyInput = 7295b42334884a41aed8fff9cc870020d71049219ee084a9cbc06bfe573b97f3
+EntropyInputReseed = ad5f770233adb60e19fbdd46e24ef65fc5098f7f91983f280b2810360d5d4a22
+AdditionalInput1 = b67d0c716aeda647c5aeb4aa4c1bebb4
+AdditionalInput2 = fb9350866c2b34eae90e3a1e9cbb51c3
+Out = 86b2265d200a34eb0be4f21c304c4ad1c4609d8ecc4b8a63da8c7fed3ead7fb93441a4050efb00b9b22d52ce59e409c06019198a9c3f32463eee24a01036cd74
+
+EntropyInput = b8dcc441b4979af9b0c35e3cd065046632f83bc6de9ea575e1ec28b3d332abeb
+EntropyInputReseed = 66f92647479dc296e4a1784a086eaf0c263eaa805d8584608b625d147c577944
+AdditionalInput1 = 9e663bfb63c5ca4395dad70ae5d7074a
+AdditionalInput2 = 19b648af3efc4fe33781c90a1bd24d25
+Out = 918049db0049c744b75a403387c430f45c86c019f925c001481ec49069b2ef08e9657a8af26c80e227017b015679331a8708c4bd06bbea4774473e7460ba242b
+
diff --git a/src/tests/test_rng.cpp b/src/tests/test_rng.cpp
index 76e0d28ea..470bddcdf 100644
--- a/src/tests/test_rng.cpp
+++ b/src/tests/test_rng.cpp
@@ -1,5 +1,5 @@
/*
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2017 Jack Lloyd
* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
@@ -16,6 +16,10 @@
#include <botan/auto_rng.h>
#endif
+#if defined(BOTAN_HAS_CHACHA_RNG)
+ #include <botan/chacha_rng.h>
+#endif
+
#if defined(BOTAN_HAS_SYSTEM_RNG)
#include <botan/system_rng.h>
#endif
@@ -62,6 +66,7 @@ class HMAC_DRBG_Tests : public Text_Based_Test
Test::Result result("HMAC_DRBG(" + algo + ")");
auto mac = Botan::MessageAuthenticationCode::create("HMAC(" + algo + ")");
+
if(!mac)
{
result.note_missing("HMAC(" + algo + ")");
@@ -603,6 +608,49 @@ BOTAN_REGISTER_TEST("hmac_drbg_unit", HMAC_DRBG_Unit_Tests);
#endif
+
+#if defined(BOTAN_HAS_CHACHA_RNG)
+
+class ChaCha_RNG_Tests : public Text_Based_Test
+ {
+ public:
+ ChaCha_RNG_Tests()
+ : Text_Based_Test("rng/chacha_rng.vec",
+ "EntropyInput,EntropyInputReseed,Out",
+ "AdditionalInput1,AdditionalInput2") {}
+
+ Test::Result run_one_test(const std::string& algo, const VarMap& vars) override
+ {
+ const std::vector<uint8_t> seed_input = get_req_bin(vars, "EntropyInput");
+ const std::vector<uint8_t> reseed_input = get_req_bin(vars, "EntropyInputReseed");
+ const std::vector<uint8_t> expected = get_req_bin(vars, "Out");
+
+ const std::vector<uint8_t> ad1 = get_opt_bin(vars, "AdditionalInput1");
+ const std::vector<uint8_t> ad2 = get_opt_bin(vars, "AdditionalInput2");
+
+ Test::Result result("ChaCha_RNG");
+
+ Botan::ChaCha_RNG rng;
+ rng.initialize_with(seed_input.data(), seed_input.size());
+
+ // now reseed
+ rng.add_entropy(reseed_input.data(), reseed_input.size());
+
+ std::vector<uint8_t> out(expected.size());
+ // first block is discarded
+ rng.randomize_with_input(out.data(), out.size(), ad1.data(), ad1.size());
+ rng.randomize_with_input(out.data(), out.size(), ad2.data(), ad2.size());
+
+ result.test_eq("rng", out, expected);
+ return result;
+ }
+
+ };
+
+BOTAN_REGISTER_TEST("chacha_rng", ChaCha_RNG_Tests);
+
+#endif
+
#if defined(BOTAN_HAS_AUTO_RNG)
class AutoSeeded_RNG_Tests : public Test