From 13b4e8564e8375758b4a5e01fa86f2ef7dcddad7 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Sat, 12 Oct 2024 09:13:42 -0400 Subject: [PATCH] Refactor performance testing of symmetric algorithms --- src/cli/perf.cpp | 2 +- src/cli/perf.h | 4 +- src/cli/perf_sym.cpp | 409 ++++++++++++++++++++++++++++++++++ src/cli/speed.cpp | 315 +------------------------- src/lib/modes/cipher_mode.cpp | 4 + src/scripts/test_cli.py | 14 +- 6 files changed, 426 insertions(+), 322 deletions(-) create mode 100644 src/cli/perf_sym.cpp diff --git a/src/cli/perf.cpp b/src/cli/perf.cpp index caf4028bd34..0e6b0a6d243 100644 --- a/src/cli/perf.cpp +++ b/src/cli/perf.cpp @@ -35,7 +35,7 @@ std::unique_ptr PerfTest::get(const std::string& name) { return i->second(); } - return nullptr; + return PerfTest::get_sym(name); } } // namespace Botan_CLI diff --git a/src/cli/perf.h b/src/cli/perf.h index 6d7a158a90a..807b4ebee3f 100644 --- a/src/cli/perf.h +++ b/src/cli/perf.h @@ -24,8 +24,6 @@ class PerfConfig { virtual std::chrono::milliseconds runtime() const = 0; - //virtual std::vector providers() const = 0; - virtual const std::vector& ecc_groups() const = 0; virtual const std::vector& buffer_sizes() const = 0; @@ -60,6 +58,8 @@ class PerfTest { }; private: + static std::unique_ptr get_sym(const std::string& alg); + static std::map& global_registry(); }; diff --git a/src/cli/perf_sym.cpp b/src/cli/perf_sym.cpp new file mode 100644 index 00000000000..3f44e2f9ec0 --- /dev/null +++ b/src/cli/perf_sym.cpp @@ -0,0 +1,409 @@ +/* +* (C) 2024 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "perf.h" +#include + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_CIPHER_MODES) + #include +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include +#endif + +#if defined(BOTAN_HAS_HASH) + #include +#endif + +#if defined(BOTAN_HAS_MAC) + #include +#endif + +#if defined(BOTAN_HAS_XOF) + #include +#endif + +namespace Botan_CLI { + +#if defined(BOTAN_HAS_BLOCK_CIPHER) +class PerfTest_BlockCipher final : public PerfTest { + public: + PerfTest_BlockCipher(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::BlockCipher::providers(m_alg)) { + if(auto cipher = Botan::BlockCipher::create(m_alg, provider)) { + bench_stream_cipher(config, *cipher); + } + } + } + + static bool has_impl_for(std::string_view alg) { return !Botan::BlockCipher::providers(alg).empty(); } + + private: + void bench_stream_cipher(const PerfConfig& config, Botan::BlockCipher& cipher) { + auto& rng = config.rng(); + const auto runtime = config.runtime(); + const auto provider = cipher.provider(); + + auto ks_timer = config.make_timer(cipher.name(), 1, "key schedule", provider); + + const Botan::SymmetricKey key(rng, cipher.maximum_keylength()); + ks_timer->run([&]() { cipher.set_key(key); }); + + const size_t bs = cipher.block_size(); + std::set buf_sizes_in_blocks; + for(size_t buf_size : config.buffer_sizes()) { + if(buf_size % bs == 0) { + buf_sizes_in_blocks.insert(buf_size); + } else { + buf_sizes_in_blocks.insert(buf_size + bs - (buf_size % bs)); + } + } + + for(size_t buf_size : buf_sizes_in_blocks) { + std::vector buffer(buf_size); + const size_t mult = std::max(1, 65536 / buf_size); + const size_t blocks = buf_size / bs; + + auto encrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size); + auto decrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "decrypt", provider, buf_size); + + encrypt_timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + cipher.encrypt_n(&buffer[0], &buffer[0], blocks); + } + }); + config.record_result(*encrypt_timer); + + decrypt_timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + cipher.decrypt_n(&buffer[0], &buffer[0], blocks); + } + }); + config.record_result(*decrypt_timer); + } + } + + std::string m_alg; +}; +#endif + +#if defined(BOTAN_HAS_CIPHER_MODES) +class PerfTest_CipherMode final : public PerfTest { + public: + PerfTest_CipherMode(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::Cipher_Mode::providers(m_alg)) { + if(auto enc = Botan::Cipher_Mode::create(m_alg, Botan::Cipher_Dir::Encryption, provider)) { + auto dec = Botan::Cipher_Mode::create_or_throw(m_alg, Botan::Cipher_Dir::Decryption, provider); + bench_cipher_mode(config, *enc, *dec); + } + } + } + + static bool has_impl_for(std::string_view alg) { return !Botan::Cipher_Mode::providers(alg).empty(); } + + private: + void bench_cipher_mode(const PerfConfig& config, Botan::Cipher_Mode& enc, Botan::Cipher_Mode& dec) { + auto& rng = config.rng(); + const auto runtime = config.runtime(); + const auto provider = enc.provider(); + + auto ks_timer = config.make_timer(enc.name(), 1, "key schedule", provider); + + const Botan::SymmetricKey key(config.rng(), enc.key_spec().maximum_keylength()); + + ks_timer->run([&]() { enc.set_key(key); }); + ks_timer->run([&]() { dec.set_key(key); }); + + config.record_result(*ks_timer); + + for(auto buf_size : config.buffer_sizes()) { + Botan::secure_vector buffer = rng.random_vec(buf_size); + const size_t mult = std::max(1, 65536 / buf_size); + + auto encrypt_timer = config.make_timer(enc.name(), mult * buffer.size(), "encrypt", provider, buf_size); + auto decrypt_timer = config.make_timer(dec.name(), mult * buffer.size(), "decrypt", provider, buf_size); + + Botan::secure_vector iv = rng.random_vec(enc.default_nonce_length()); + + if(buf_size >= enc.minimum_final_size()) { + encrypt_timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + enc.start(iv); + enc.finish(buffer); + buffer.resize(buf_size); // remove any tag or padding + } + }); + + while(decrypt_timer->under(runtime)) { + if(!iv.empty()) { + iv[iv.size() - 1] += 1; + } + + // Create a valid ciphertext/tag for decryption to run on + buffer.resize(buf_size); + enc.start(iv); + enc.finish(buffer); + + Botan::secure_vector dbuffer; + + decrypt_timer->run([&]() { + for(size_t i = 0; i != mult; ++i) { + dbuffer = buffer; + dec.start(iv); + dec.finish(dbuffer); + } + }); + } + } + + config.record_result(*encrypt_timer); + config.record_result(*decrypt_timer); + } + } + + std::string m_alg; +}; +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) +class PerfTest_StreamCipher final : public PerfTest { + public: + PerfTest_StreamCipher(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::StreamCipher::providers(m_alg)) { + if(auto cipher = Botan::StreamCipher::create(m_alg, provider)) { + bench_stream_cipher(config, *cipher); + } + } + } + + static bool has_impl_for(std::string_view alg) { return !Botan::StreamCipher::providers(alg).empty(); } + + private: + void bench_stream_cipher(const PerfConfig& config, Botan::StreamCipher& cipher) { + auto& rng = config.rng(); + const auto runtime = config.runtime(); + const auto provider = cipher.provider(); + + for(auto buf_size : config.buffer_sizes()) { + const Botan::SymmetricKey key(rng, cipher.maximum_keylength()); + cipher.set_key(key); + + if(cipher.valid_iv_length(12)) { + const Botan::InitializationVector iv(rng, 12); + cipher.set_iv(iv.begin(), iv.size()); + } + + auto buffer = rng.random_vec(buf_size); + + const size_t mult = std::max(1, 65536 / buf_size); + + auto encrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size); + + encrypt_timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + cipher.encipher(buffer); + } + }); + + config.record_result(*encrypt_timer); + + auto ks_timer = config.make_timer(cipher.name(), buffer.size(), "write_keystream", provider, buf_size); + + while(ks_timer->under(runtime)) { + ks_timer->run([&]() { cipher.write_keystream(buffer.data(), buffer.size()); }); + } + config.record_result(*ks_timer); + } + } + + std::string m_alg; +}; +#endif + +#if defined(BOTAN_HAS_HASH) +class PerfTest_HashFunction final : public PerfTest { + public: + PerfTest_HashFunction(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::HashFunction::providers(m_alg)) { + if(auto hash = Botan::HashFunction::create(m_alg, provider)) { + bench_hash_fn(config, *hash); + } + } + } + + static bool has_impl_for(std::string_view alg) { return !Botan::HashFunction::providers(alg).empty(); } + + private: + void bench_hash_fn(const PerfConfig& config, Botan::HashFunction& hash) { + std::vector output(hash.output_length()); + const auto provider = hash.provider(); + const auto runtime = config.runtime(); + + for(auto buf_size : config.buffer_sizes()) { + const auto buffer = config.rng().random_vec(buf_size); + + const size_t mult = std::max(1, 65536 / buf_size); + + auto timer = config.make_timer(hash.name(), mult * buffer.size(), "hash", provider, buf_size); + timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + hash.update(buffer); + hash.final(output.data()); + } + }); + config.record_result(*timer); + } + } + + std::string m_alg; +}; +#endif + +#if defined(BOTAN_HAS_MAC) +class PerfTest_MessageAuthenticationCode final : public PerfTest { + public: + PerfTest_MessageAuthenticationCode(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::MessageAuthenticationCode::providers(m_alg)) { + if(auto mac = Botan::MessageAuthenticationCode::create(m_alg, provider)) { + bench_mac_fn(config, *mac); + } + } + } + + static bool has_impl_for(std::string_view alg) { + return !Botan::MessageAuthenticationCode::providers(alg).empty(); + } + + private: + void bench_mac_fn(const PerfConfig& config, Botan::MessageAuthenticationCode& mac) { + std::vector output(mac.output_length()); + const auto provider = mac.provider(); + const auto runtime = config.runtime(); + auto& rng = config.rng(); + + for(auto buf_size : config.buffer_sizes()) { + Botan::secure_vector buffer = rng.random_vec(buf_size); + const size_t mult = std::max(1, 65536 / buf_size); + + const Botan::SymmetricKey key(rng, mac.maximum_keylength()); + mac.set_key(key); + + auto timer = config.make_timer(mac.name(), mult * buffer.size(), "mac", provider, buf_size); + timer->run_until_elapsed(runtime, [&]() { + for(size_t i = 0; i != mult; ++i) { + if(mac.fresh_key_required_per_message()) { + mac.set_key(key); + } + mac.start(nullptr, 0); + mac.update(buffer); + mac.final(output.data()); + } + }); + + config.record_result(*timer); + } + } + + std::string m_alg; +}; +#endif + +#if defined(BOTAN_HAS_XOF) +class PerfTest_XOF final : public PerfTest { + public: + PerfTest_XOF(std::string_view alg) : m_alg(alg) {} + + void go(const PerfConfig& config) override { + for(const auto& provider : Botan::XOF::providers(m_alg)) { + if(auto xof = Botan::XOF::create(m_alg, provider)) { + bench_xof_fn(config, *xof); + } + } + } + + static bool has_impl_for(std::string_view alg) { return !Botan::XOF::providers(alg).empty(); } + + private: + void bench_xof_fn(const PerfConfig& config, Botan::XOF& xof) { + const auto runtime = config.runtime(); + const auto provider = xof.provider(); + + for(size_t buf_size : config.buffer_sizes()) { + auto in = config.rng().random_vec(buf_size); + Botan::secure_vector out(buf_size); + + auto in_timer = config.make_timer(xof.name(), in.size(), "input", provider, buf_size); + in_timer->run_until_elapsed(runtime / 2, [&]() { xof.update(in); }); + + auto out_timer = config.make_timer(xof.name(), out.size(), "output", provider, buf_size); + out_timer->run_until_elapsed(runtime / 2, [&] { xof.output(out); }); + + config.record_result(*in_timer); + config.record_result(*out_timer); + } + } + + std::string m_alg; +}; +#endif + +//static +std::unique_ptr PerfTest::get_sym(const std::string& alg) { +#if defined(BOTAN_HAS_XOF) + if(PerfTest_XOF::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + if(PerfTest_StreamCipher::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + if(PerfTest_BlockCipher::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + +#if defined(BOTAN_HAS_CIPHER_MODES) + if(PerfTest_CipherMode::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + +#if defined(BOTAN_HAS_HASH) + if(PerfTest_HashFunction::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + +#if defined(BOTAN_HAS_MAC) + if(PerfTest_MessageAuthenticationCode::has_impl_for(alg)) { + return std::make_unique(alg); + } +#endif + + return {}; +} + +} // namespace Botan_CLI diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp index e2e195d586e..1797be1a3ae 100644 --- a/src/cli/speed.cpp +++ b/src/cli/speed.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -24,30 +23,6 @@ #include #include -#if defined(BOTAN_HAS_BLOCK_CIPHER) - #include -#endif - -#if defined(BOTAN_HAS_STREAM_CIPHER) - #include -#endif - -#if defined(BOTAN_HAS_HASH) - #include -#endif - -#if defined(BOTAN_HAS_XOF) - #include -#endif - -#if defined(BOTAN_HAS_CIPHER_MODES) - #include -#endif - -#if defined(BOTAN_HAS_MAC) - #include -#endif - #if defined(BOTAN_HAS_ECC_GROUP) #include #endif @@ -223,7 +198,7 @@ class Speed final : public Command { public: Speed() : Command( - "speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos") { + "speed --msec=500 --format=default --ecc-groups= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos") { } static std::vector default_benchmark_list() { @@ -322,7 +297,6 @@ class Speed final : public Command { void go() override { std::chrono::milliseconds msec(get_arg_sz("msec")); - const std::string provider = get_arg("provider"); std::vector ecc_groups = Command::split_on(get_arg("ecc-groups"), ','); const std::string format = get_arg("format"); const std::string clock_ratio = get_arg("cpu-clock-ratio"); @@ -432,47 +406,8 @@ class Speed final : public Command { if(auto perf = PerfTest::get(algo)) { perf->go(perf_config); - } -#if defined(BOTAN_HAS_HASH) - else if(!Botan::HashFunction::providers(algo).empty()) { - bench_providers_of( - algo, provider, msec, buf_sizes, std::bind(&Speed::bench_hash, this, _1, _2, _3, _4)); - } -#endif -#if defined(BOTAN_HAS_XOF) - else if(!Botan::XOF::providers(algo).empty()) { - bench_providers_of( - algo, provider, msec, buf_sizes, std::bind(&Speed::bench_xof, this, _1, _2, _3, _4)); - } -#endif -#if defined(BOTAN_HAS_BLOCK_CIPHER) - else if(!Botan::BlockCipher::providers(algo).empty()) { - bench_providers_of( - algo, provider, msec, buf_sizes, std::bind(&Speed::bench_block_cipher, this, _1, _2, _3, _4)); - } -#endif -#if defined(BOTAN_HAS_STREAM_CIPHER) - else if(!Botan::StreamCipher::providers(algo).empty()) { - bench_providers_of( - algo, provider, msec, buf_sizes, std::bind(&Speed::bench_stream_cipher, this, _1, _2, _3, _4)); - } -#endif -#if defined(BOTAN_HAS_CIPHER_MODES) - else if(auto enc = Botan::Cipher_Mode::create(algo, Botan::Cipher_Dir::Encryption, provider)) { - auto dec = Botan::Cipher_Mode::create_or_throw(algo, Botan::Cipher_Dir::Decryption, provider); - bench_cipher_mode(*enc, *dec, msec, buf_sizes); - } -#endif -#if defined(BOTAN_HAS_MAC) - else if(!Botan::MessageAuthenticationCode::providers(algo).empty()) { - bench_providers_of( - algo, provider, msec, buf_sizes, std::bind(&Speed::bench_mac, this, _1, _2, _3, _4)); - } -#endif - else { - if(verbose() || !using_defaults) { - error_output() << "Unknown algorithm '" << algo << "'\n"; - } + } else if(verbose() || !using_defaults) { + error_output() << "Unknown algorithm '" << algo << "'\n"; } } @@ -514,26 +449,6 @@ class Speed final : public Command { void record_result(const std::unique_ptr& t) { record_result(*t); } - template - using bench_fn = std::function&)>; - - template - void bench_providers_of(const std::string& algo, - const std::string& provider, /* user request, if any */ - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes, - bench_fn bench_one) { - for(const auto& prov : T::providers(algo)) { - if(provider.empty() || provider == prov) { - auto p = T::create(algo, prov); - - if(p) { - bench_one(*p, prov, runtime, buf_sizes); - } - } - } - } - std::unique_ptr make_timer(const std::string& name, uint64_t event_mult = 1, const std::string& what = "", @@ -541,230 +456,6 @@ class Speed final : public Command { size_t buf_size = 0) { return std::make_unique(name, provider, what, event_mult, buf_size, m_clock_cycle_ratio, m_clock_speed); } - - std::unique_ptr make_timer(const std::string& algo, const std::string& provider, const std::string& what) { - return make_timer(algo, 1, what, provider, 0); - } - -#if defined(BOTAN_HAS_BLOCK_CIPHER) - void bench_block_cipher(Botan::BlockCipher& cipher, - const std::string& provider, - std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - auto ks_timer = make_timer(cipher.name(), provider, "key schedule"); - - const Botan::SymmetricKey key(rng(), cipher.maximum_keylength()); - ks_timer->run([&]() { cipher.set_key(key); }); - - const size_t bs = cipher.block_size(); - std::set buf_sizes_in_blocks; - for(size_t buf_size : buf_sizes) { - if(buf_size % bs == 0) { - buf_sizes_in_blocks.insert(buf_size); - } else { - buf_sizes_in_blocks.insert(buf_size + bs - (buf_size % bs)); - } - } - - for(size_t buf_size : buf_sizes_in_blocks) { - std::vector buffer(buf_size); - const size_t mult = std::max(1, 65536 / buf_size); - const size_t blocks = buf_size / bs; - - auto encrypt_timer = make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size); - auto decrypt_timer = make_timer(cipher.name(), mult * buffer.size(), "decrypt", provider, buf_size); - - encrypt_timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - cipher.encrypt_n(&buffer[0], &buffer[0], blocks); - } - }); - record_result(encrypt_timer); - - decrypt_timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - cipher.decrypt_n(&buffer[0], &buffer[0], blocks); - } - }); - record_result(decrypt_timer); - } - } -#endif - -#if defined(BOTAN_HAS_STREAM_CIPHER) - void bench_stream_cipher(Botan::StreamCipher& cipher, - const std::string& provider, - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - for(auto buf_size : buf_sizes) { - const Botan::SymmetricKey key(rng(), cipher.maximum_keylength()); - cipher.set_key(key); - - if(cipher.valid_iv_length(12)) { - const Botan::InitializationVector iv(rng(), 12); - cipher.set_iv(iv.begin(), iv.size()); - } - - Botan::secure_vector buffer = rng().random_vec(buf_size); - - const size_t mult = std::max(1, 65536 / buf_size); - - auto encrypt_timer = make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size); - - encrypt_timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - cipher.encipher(buffer); - } - }); - - record_result(encrypt_timer); - - if(verbose()) { - auto ks_timer = make_timer(cipher.name(), buffer.size(), "write_keystream", provider, buf_size); - - while(ks_timer->under(runtime)) { - ks_timer->run([&]() { cipher.write_keystream(buffer.data(), buffer.size()); }); - } - record_result(ks_timer); - } - } - } -#endif - -#if defined(BOTAN_HAS_HASH) - void bench_hash(Botan::HashFunction& hash, - const std::string& provider, - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - std::vector output(hash.output_length()); - - for(auto buf_size : buf_sizes) { - Botan::secure_vector buffer = rng().random_vec(buf_size); - - const size_t mult = std::max(1, 65536 / buf_size); - - auto timer = make_timer(hash.name(), mult * buffer.size(), "hash", provider, buf_size); - timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - hash.update(buffer); - hash.final(output.data()); - } - }); - record_result(timer); - } - } -#endif - -#if defined(BOTAN_HAS_XOF) - void bench_xof(Botan::XOF& xof, - const std::string& provider, - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - for(auto buf_size : buf_sizes) { - Botan::secure_vector in = rng().random_vec(buf_size); - Botan::secure_vector out(buf_size); - - auto in_timer = make_timer(xof.name(), in.size(), "input", provider, buf_size); - in_timer->run_until_elapsed(runtime / 2, [&]() { xof.update(in); }); - - auto out_timer = make_timer(xof.name(), out.size(), "output", provider, buf_size); - out_timer->run_until_elapsed(runtime / 2, [&] { xof.output(out); }); - - record_result(in_timer); - record_result(out_timer); - } - } -#endif - -#if defined(BOTAN_HAS_MAC) - void bench_mac(Botan::MessageAuthenticationCode& mac, - const std::string& provider, - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - std::vector output(mac.output_length()); - - for(auto buf_size : buf_sizes) { - Botan::secure_vector buffer = rng().random_vec(buf_size); - const size_t mult = std::max(1, 65536 / buf_size); - - const Botan::SymmetricKey key(rng(), mac.maximum_keylength()); - mac.set_key(key); - - auto timer = make_timer(mac.name(), mult * buffer.size(), "mac", provider, buf_size); - timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - if(mac.fresh_key_required_per_message()) { - mac.set_key(key); - } - mac.start(nullptr, 0); - mac.update(buffer); - mac.final(output.data()); - } - }); - - record_result(timer); - } - } -#endif - -#if defined(BOTAN_HAS_CIPHER_MODES) - void bench_cipher_mode(Botan::Cipher_Mode& enc, - Botan::Cipher_Mode& dec, - const std::chrono::milliseconds runtime, - const std::vector& buf_sizes) { - auto ks_timer = make_timer(enc.name(), enc.provider(), "key schedule"); - - const Botan::SymmetricKey key(rng(), enc.key_spec().maximum_keylength()); - - ks_timer->run([&]() { enc.set_key(key); }); - ks_timer->run([&]() { dec.set_key(key); }); - - record_result(ks_timer); - - for(auto buf_size : buf_sizes) { - Botan::secure_vector buffer = rng().random_vec(buf_size); - const size_t mult = std::max(1, 65536 / buf_size); - - auto encrypt_timer = make_timer(enc.name(), mult * buffer.size(), "encrypt", enc.provider(), buf_size); - auto decrypt_timer = make_timer(dec.name(), mult * buffer.size(), "decrypt", dec.provider(), buf_size); - - Botan::secure_vector iv = rng().random_vec(enc.default_nonce_length()); - - if(buf_size >= enc.minimum_final_size()) { - encrypt_timer->run_until_elapsed(runtime, [&]() { - for(size_t i = 0; i != mult; ++i) { - enc.start(iv); - enc.finish(buffer); - buffer.resize(buf_size); // remove any tag or padding - } - }); - - while(decrypt_timer->under(runtime)) { - if(!iv.empty()) { - iv[iv.size() - 1] += 1; - } - - // Create a valid ciphertext/tag for decryption to run on - buffer.resize(buf_size); - enc.start(iv); - enc.finish(buffer); - - Botan::secure_vector dbuffer; - - decrypt_timer->run([&]() { - for(size_t i = 0; i != mult; ++i) { - dbuffer = buffer; - dec.start(iv); - dec.finish(dbuffer); - } - }); - } - } - record_result(encrypt_timer); - record_result(decrypt_timer); - } - } -#endif }; BOTAN_REGISTER_COMMAND("speed", Speed); diff --git a/src/lib/modes/cipher_mode.cpp b/src/lib/modes/cipher_mode.cpp index 0b966165311..cd3282585e1 100644 --- a/src/lib/modes/cipher_mode.cpp +++ b/src/lib/modes/cipher_mode.cpp @@ -61,6 +61,10 @@ std::unique_ptr Cipher_Mode::create(std::string_view algo, } #endif + if(provider != "base" && !provider.empty()) { + return nullptr; + } + #if defined(BOTAN_HAS_STREAM_CIPHER) if(auto sc = StreamCipher::create(algo)) { return std::make_unique(std::move(sc)); diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index ca060cf509e..ffa2d2e412d 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -530,7 +530,7 @@ def cli_key_tests(tmp_dir): valid_sig = "nI4mI1ec14Y7nYUWs2edysAVvkob0TWpmGh5rrYWDA+/W9Fj0ZM21qJw8qa3/avAOIVBO6hoMEVmfJYXlS+ReA==" - test_cli("sign", "--provider=base %s %s" % (priv_key, pub_key), valid_sig) + test_cli("sign", "%s %s" % (priv_key, pub_key), valid_sig) test_cli("verify", [pub_key, pub_key, '-'], "Signature is valid", valid_sig) @@ -1570,7 +1570,7 @@ def cli_pk_encrypt_tests(tmp_dir): rsa_priv_key = os.path.join(tmp_dir, 'rsa.priv') rsa_pub_key = os.path.join(tmp_dir, 'rsa.pub') - test_cli("keygen", ["--algo=RSA", "--provider=base", "--params=2048", "--output=%s" % (rsa_priv_key)], "") + test_cli("keygen", ["--algo=RSA", "--params=2048", "--output=%s" % (rsa_priv_key)], "") key_hash = "D1621B7D1272545F8CCC220BC7F6F5BAF0150303B19299F0C5B79C095B3CDFC0" test_cli("hash", ["--no-fsname", "--algo=SHA-256", rsa_priv_key], key_hash) @@ -1649,11 +1649,11 @@ def cli_speed_table_tests(_tmp_dir): version_re = re.compile(r'^Botan 3\.[0-9]+\.[0-9](\-.*[0-9]+)? \(.*, revision .*, distribution .*\)') cpuid_re = re.compile(r'^CPUID: [a-z_0-9 ]*$') - format_re = re.compile(r'^AES-128 .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + format_re = re.compile(r'^.* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') tbl_hdr_re = re.compile(r'^algo +operation +1024 bytes$') - tbl_val_re = re.compile(r'^AES-128 +(encrypt|decrypt) +[0-9]+(\.[0-9]{2})$') + tbl_val_re = re.compile(r'^.* +(encrypt|decrypt) +[0-9]+(\.[0-9]{2})$') - output = test_cli("speed", ["--format=table", "--provider=base", "--msec=%d" % (msec), "AES-128"], None).split('\n') + output = test_cli("speed", ["--format=table", "--msec=%d" % (msec), "AES-128"], None).split('\n') if len(output) != 11: logging.error('Unexpected number of lines from table output') @@ -1686,7 +1686,7 @@ def cli_speed_table_tests(_tmp_dir): logging.error("Unexpected trailing message got %s", output[10]) def cli_speed_invalid_option_tests(_tmp_dir): - speed_usage = "Usage: speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos" + speed_usage = "Usage: speed --msec=500 --format=default --ecc-groups= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos" test_cli("speed", ["--buf-size=0", "--msec=1", "AES-128"], expected_stderr="Usage error: Cannot have a zero-sized buffer\n%s" % (speed_usage)) @@ -1723,7 +1723,7 @@ def cli_speed_tests(_tmp_dir): if len(output) % 4 != 0: logging.error("Unexpected number of lines for AES-128 speed test") - format_re = re.compile(r'^AES-128 .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') + format_re = re.compile(r'^.* .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') for line in output: if format_re.match(line) is None: logging.error("Unexpected line %s", line)