diff options
author | Jack Lloyd <[email protected]> | 2019-08-27 10:05:49 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2019-08-27 20:04:21 -0400 |
commit | b4543c801cde2874b982bbaccba471bd14c27810 (patch) | |
tree | fd918d86ed4d114203a0c137abbbf19b66739052 | |
parent | ecb22c16531db3023c739fa1436d8f3893fa1081 (diff) |
Add a cmdlet which allows sampling/testing raw entropy sources
-rw-r--r-- | src/cli/entropy.cpp | 104 | ||||
-rwxr-xr-x | src/scripts/test_cli.py | 24 |
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, |