aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2019-08-27 10:05:49 -0400
committerJack Lloyd <[email protected]>2019-08-27 20:04:21 -0400
commitb4543c801cde2874b982bbaccba471bd14c27810 (patch)
treefd918d86ed4d114203a0c137abbbf19b66739052
parentecb22c16531db3023c739fa1436d8f3893fa1081 (diff)
Add a cmdlet which allows sampling/testing raw entropy sources
-rw-r--r--src/cli/entropy.cpp104
-rwxr-xr-xsrc/scripts/test_cli.py24
2 files changed, 128 insertions, 0 deletions
diff --git a/src/cli/entropy.cpp b/src/cli/entropy.cpp
new file mode 100644
index 000000000..0404afb99
--- /dev/null
+++ b/src/cli/entropy.cpp
@@ -0,0 +1,104 @@
+/*
+* (C) 2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+#include "../tests/test_rng.h" // FIXME
+
+#include <botan/entropy_src.h>
+
+#if defined(BOTAN_HAS_COMPRESSION)
+#include <botan/compression.h>
+#endif
+
+namespace Botan_CLI {
+
+class Entropy final : public Command
+ {
+ public:
+ Entropy() : Command("entropy --truncate-at=128 source") {}
+
+ std::string group() const override
+ {
+ return "misc";
+ }
+
+ std::string description() const override
+ {
+ return "Sample a raw entropy source";
+ }
+
+ void go() override
+ {
+ const std::string req_source = get_arg("source");
+ const size_t truncate_sample = get_arg_sz("truncate-at");
+
+ auto& entropy_sources = Botan::Entropy_Sources::global_sources();
+
+ std::vector<std::string> sources;
+ if(req_source == "all")
+ sources = entropy_sources.enabled_sources();
+ else
+ sources.push_back(req_source);
+
+ for(std::string source : sources)
+ {
+ Botan_Tests::SeedCapturing_RNG rng;
+ const size_t entropy_estimate = entropy_sources.poll_just(rng, source);
+
+ if(rng.samples() == 0)
+ {
+ output() << "Source " << source << " is unavailable\n";
+ continue;
+ }
+
+ const auto& sample = rng.seed_material();
+
+ output() << "Polling " << source << " gathered " << sample.size()
+ << " bytes in " << rng.samples() << " outputs with estimated entropy "
+ << entropy_estimate << "\n";
+
+#if defined(BOTAN_HAS_COMPRESSION)
+ if(!sample.empty())
+ {
+ std::unique_ptr<Botan::Compression_Algorithm> comp(Botan::make_compressor("zlib"));
+ if(comp)
+ {
+ try
+ {
+ Botan::secure_vector<uint8_t> compressed;
+ compressed.assign(sample.begin(), sample.end());
+ comp->start(9);
+ comp->finish(compressed);
+
+ if(compressed.size() < sample.size())
+ {
+ output() << "Sample from " << source << " was zlib compressed from " << sample.size()
+ << " bytes to " << compressed.size() << " bytes\n";
+ }
+ }
+ catch(std::exception& e)
+ {
+ error_output() << "Error while attempting to compress: " << e.what() << "\n";
+ }
+ }
+ }
+#endif
+
+ if(sample.size() <= truncate_sample)
+ {
+ output() << Botan::hex_encode(sample) << "\n";
+ }
+ else if(truncate_sample > 0)
+ {
+ output() << Botan::hex_encode(&sample[0], truncate_sample) << "...\n";
+ }
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("entropy", Entropy);
+
+}
diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py
index eaff50a16..e6e858909 100755
--- a/src/scripts/test_cli.py
+++ b/src/scripts/test_cli.py
@@ -149,6 +149,29 @@ def cli_gen_prime_tests(_tmp_dir):
test_cli("gen_prime", "64", "15568813029901363163")
test_cli("gen_prime", "128", "287193909494025008847286845478788766073")
+def cli_entropy_tests(_tmp_dir):
+ output = test_cli("entropy", ["all"], None)
+
+ status_re = re.compile('Polling [a-z0-9_]+ gathered [0-9]+ bytes in [0-9]+ outputs with estimated entropy [0-9]+')
+ unavail_re = re.compile('Source [a-z0-9_]+ is unavailable')
+ output_re = re.compile('[A-F0-9]+(\.\.\.)?')
+
+ status_next = True
+
+ for i,line in zip(range(len(output)), output.split('\n')):
+ if status_next:
+ if status_re.match(line) is not None:
+ status_next = False
+ elif unavail_re.match(line) is not None:
+ pass
+ else:
+ logging.error('Unexpected status line %s', line)
+ status_next = False
+ else:
+ if output_re.match(line) is None:
+ logging.error('Unexpected sample line %s', line)
+ status_next = True
+
def cli_factor_tests(_tmp_dir):
test_cli("factor", "97", "97: 97")
test_cli("factor", "9753893489562389", "9753893489562389: 21433 455087644733")
@@ -1057,6 +1080,7 @@ def main(args=None):
cli_cpuid_tests,
cli_dl_group_info_tests,
cli_ec_group_info_tests,
+ cli_entropy_tests,
cli_factor_tests,
cli_gen_dl_group_tests,
cli_gen_prime_tests,