Repository: randombit/botan
Pull request #1848 (2019-03-01 00:27:51)

Split CLI utils.cpp into more parts
Add base58 encoding/decoding CLI

Use decrypt_or_random in pk_decrypt


Patch:
diff --git a/src/cli/cli_rng.cpp b/src/cli/cli_rng.cpp
index 78af51314..90b30a820 100644
--- a/src/cli/cli_rng.cpp
+++ b/src/cli/cli_rng.cpp
@@ -9,6 +9,7 @@
 #include <botan/entropy_src.h>
 #include <botan/cpuid.h>
 #include <botan/hex.h>
+#include <botan/parsing.h>
 
 #if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
    #include <botan/auto_rng.h>
@@ -86,4 +87,47 @@ cli_make_rng(const std::string& rng_type, const std::string& hex_drbg_seed)
    throw CLI_Error_Unsupported("RNG", rng_type);
    }
 
+class RNG final : public Command
+   {
+   public:
+      RNG() : Command("rng --system --rdrand --auto --entropy --drbg --drbg-seed= *bytes") {}
+
+      std::string group() const override
+         {
+         return "misc";
+         }
+
+      std::string description() const override
+         {
+         return "Sample random bytes from the specified rng";
+         }
+
+      void go() override
+         {
+         std::string type = get_arg("rng-type");
+
+         if(type.empty())
+            {
+            for(std::string flag : { "system", "rdrand", "auto", "entropy", "drbg" })
+               {
+               if(flag_set(flag))
+                  {
+                  type = flag;
+                  break;
+                  }
+               }
+            }
+
+         const std::string drbg_seed = get_arg("drbg-seed");
+         std::unique_ptr<Botan::RandomNumberGenerator> rng = cli_make_rng(type, drbg_seed);
+
+         for(const std::string& req : get_arg_list("bytes"))
+            {
+            output() << Botan::hex_encode(rng->random_vec(Botan::to_u32bit(req))) << "\n";
+            }
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("rng", RNG);
+
 }
diff --git a/src/cli/codec.cpp b/src/cli/codec.cpp
new file mode 100644
index 000000000..0d3df336d
--- /dev/null
+++ b/src/cli/codec.cpp
@@ -0,0 +1,204 @@
+/*
+* (C) 2019 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#if defined(BOTAN_HAS_HEX_CODEC)
+   #include <botan/hex.h>
+#endif
+
+#if defined(BOTAN_HAS_BASE58_CODEC)
+   #include <botan/base58.h>
+#endif
+
+#if defined(BOTAN_HAS_BASE64_CODEC)
+   #include <botan/base64.h>
+#endif
+
+namespace Botan_CLI {
+
+#if defined(BOTAN_HAS_HEX_CODEC)
+
+class Hex_Encode final : public Command
+   {
+   public:
+      Hex_Encode() : Command("hex_enc file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Hex encode a given file";
+         }
+
+      void go() override
+         {
+         auto hex_enc_f = [&](const uint8_t b[], size_t l) { output() << Botan::hex_encode(b, l); };
+         this->read_file(get_arg("file"), hex_enc_f, 2);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("hex_enc", Hex_Encode);
+
+class Hex_Decode final : public Command
+   {
+   public:
+      Hex_Decode() : Command("hex_dec file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Hex decode a given file";
+         }
+
+      void go() override
+         {
+         auto hex_dec_f = [&](const uint8_t b[], size_t l)
+            {
+            std::vector<uint8_t> bin = Botan::hex_decode(reinterpret_cast<const char*>(b), l);
+            output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
+            };
+
+         this->read_file(get_arg("file"), hex_dec_f, 2);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("hex_dec", Hex_Decode);
+
+#endif
+
+#if defined(BOTAN_HAS_BASE58_CODEC)
+
+class Base58_Encode final : public Command
+   {
+   public:
+      Base58_Encode() : Command("base58_enc --check file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Encode given file to Base58";
+         }
+
+      void go() override
+         {
+         auto data = slurp_file(get_arg("file"));
+
+         if(flag_set("check"))
+            output() << Botan::base58_check_encode(data);
+         else
+            output() << Botan::base58_encode(data);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base58_enc", Base58_Encode);
+
+class Base58_Decode final : public Command
+   {
+   public:
+      Base58_Decode() : Command("base58_dec --check file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Decode Base58 encoded file";
+         }
+
+      void go() override
+         {
+         auto data = slurp_file_as_str(get_arg("file"));
+
+         std::vector<uint8_t> bin;
+
+         if(flag_set("check"))
+            bin = Botan::base58_check_decode(data);
+         else
+            bin = Botan::base58_decode(data);
+
+         output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base58_dec", Base58_Decode);
+
+#endif // base64
+
+#if defined(BOTAN_HAS_BASE64_CODEC)
+
+class Base64_Encode final : public Command
+   {
+   public:
+      Base64_Encode() : Command("base64_enc file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Encode given file to Base64";
+         }
+
+      void go() override
+         {
+         auto onData = [&](const uint8_t b[], size_t l)
+            {
+            output() << Botan::base64_encode(b, l);
+            };
+         this->read_file(get_arg("file"), onData, 768);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base64_enc", Base64_Encode);
+
+class Base64_Decode final : public Command
+   {
+   public:
+      Base64_Decode() : Command("base64_dec file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Decode Base64 encoded file";
+         }
+
+      void go() override
+         {
+         auto write_bin = [&](const uint8_t b[], size_t l)
+            {
+            Botan::secure_vector<uint8_t> bin = Botan::base64_decode(reinterpret_cast<const char*>(b), l);
+            output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
+            };
+
+         this->read_file(get_arg("file"), write_bin, 1024);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base64_dec", Base64_Decode);
+
+#endif // base64
+
+}
diff --git a/src/cli/hmac.cpp b/src/cli/hmac.cpp
new file mode 100644
index 000000000..5b7345c50
--- /dev/null
+++ b/src/cli/hmac.cpp
@@ -0,0 +1,78 @@
+/*
+* (C) 2009,2010,2014,2015 Jack Lloyd
+* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#include <botan/hex.h>
+
+#if defined(BOTAN_HAS_MAC)
+   #include <botan/mac.h>
+#endif
+
+namespace Botan_CLI {
+
+#if defined(BOTAN_HAS_HMAC)
+
+class HMAC final : public Command
+   {
+   public:
+      HMAC() : Command("hmac --hash=SHA-256 --buf-size=4096 --no-fsname key *files") {}
+
+      std::string group() const override
+         {
+         return "hmac";
+         }
+
+      std::string description() const override
+         {
+         return "Compute the HMAC tag of given file(s)";
+         }
+
+      void go() override
+         {
+         const bool no_fsname = flag_set("no-fsname");
+         const std::string hash_algo = get_arg("hash");
+         std::unique_ptr<Botan::MessageAuthenticationCode> hmac =
+            Botan::MessageAuthenticationCode::create("HMAC(" + hash_algo + ")");
+
+         if(!hmac)
+            { throw CLI_Error_Unsupported("HMAC", hash_algo); }
+
+         hmac->set_key(slurp_file(get_arg("key")));
+
+         const size_t buf_size = get_arg_sz("buf-size");
+
+         std::vector<std::string> files = get_arg_list("files");
+         if(files.empty())
+            { files.push_back("-"); } // read stdin if no arguments on command line
+
+         for(const std::string& fsname : files)
+            {
+            try
+               {
+               auto update_hmac = [&](const uint8_t b[], size_t l) { hmac->update(b, l); };
+               read_file(fsname, update_hmac, buf_size);
+               output() << Botan::hex_encode(hmac->final());
+
+               if(no_fsname == false)
+                  output() << " " << fsname;
+
+               output() << "\n";
+               }
+            catch(CLI_IO_Error& e)
+               {
+               error_output() << e.what() << "\n";
+               }
+            }
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("hmac", HMAC);
+
+#endif // hmac
+
+}
diff --git a/src/cli/pk_crypt.cpp b/src/cli/pk_crypt.cpp
index 9b7f50746..4888a742f 100644
--- a/src/cli/pk_crypt.cpp
+++ b/src/cli/pk_crypt.cpp
@@ -189,13 +189,19 @@ class PK_Decrypt final : public Command
             return set_return_code(1);
             }
 
-         Botan::PK_Decryptor_EME dec(*key, rng(), "OAEP(" + oaep_hash + ")");
-
-         const Botan::secure_vector<uint8_t> file_key = dec.decrypt(encrypted_key);
-
          std::unique_ptr<Botan::AEAD_Mode> aead =
             Botan::AEAD_Mode::create_or_throw(aead_algo, Botan::DECRYPTION);
 
+         const size_t expected_keylen = aead->key_spec().maximum_keylength();
+
+         Botan::PK_Decryptor_EME dec(*key, rng(), "OAEP(" + oaep_hash + ")");
+
+         const Botan::secure_vector<uint8_t> file_key =
+            dec.decrypt_or_random(encrypted_key.data(),
+                                  encrypted_key.size(),
+                                  expected_keylen,
+                                  rng());
+
          aead->set_key(file_key);
          aead->set_associated_data_vec(encrypted_key);
          aead->start(nonce);
diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp
index c9075e2f8..2de6b0ccb 100644
--- a/src/cli/utils.cpp
+++ b/src/cli/utils.cpp
@@ -8,23 +8,11 @@
 #include "cli.h"
 
 #include <botan/version.h>
-#include <botan/rng.h>
 #include <botan/cpuid.h>
-#include <botan/hex.h>
-#include <botan/parsing.h>
 #include <botan/internal/stl_util.h>
 #include <sstream>
-#include <iterator>
 #include <iomanip>
 
-#if defined(BOTAN_HAS_MAC)
-   #include <botan/mac.h>
-#endif
-
-#if defined(BOTAN_HAS_BASE64_CODEC)
-   #include <botan/base64.h>
-#endif
-
 #if defined(BOTAN_HAS_HTTP_UTIL)
    #include <botan/http_util.h>
 #endif
@@ -261,49 +249,6 @@ class Print_Cpuid final : public Command
 
 BOTAN_REGISTER_COMMAND("cpuid", Print_Cpuid);
 
-class RNG final : public Command
-   {
-   public:
-      RNG() : Command("rng --system --rdrand --auto --entropy --drbg --drbg-seed= *bytes") {}
-
-      std::string group() const override
-         {
-         return "misc";
-         }
-
-      std::string description() const override
-         {
-         return "Sample random bytes from the specified rng";
-         }
-
-      void go() override
-         {
-         std::string type = get_arg("rng-type");
-
-         if(type.empty())
-            {
-            for(std::string flag : { "system", "rdrand", "auto", "entropy", "drbg" })
-               {
-               if(flag_set(flag))
-                  {
-                  type = flag;
-                  break;
-                  }
-               }
-            }
-
-         const std::string drbg_seed = get_arg("drbg-seed");
-         std::unique_ptr<Botan::RandomNumberGenerator> rng = cli_make_rng(type, drbg_seed);
-
-         for(const std::string& req : get_arg_list("bytes"))
-            {
-            output() << Botan::hex_encode(rng->random_vec(Botan::to_u32bit(req))) << "\n";
-            }
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("rng", RNG);
-
 #if defined(BOTAN_HAS_HTTP_UTIL)
 
 class HTTP_Get final : public Command
@@ -335,181 +280,4 @@ BOTAN_REGISTER_COMMAND("http_get", HTTP_Get);
 
 #endif // http_util
 
-#if defined(BOTAN_HAS_HEX_CODEC)
-
-class Hex_Encode final : public Command
-   {
-   public:
-      Hex_Encode() : Command("hex_enc file") {}
-
-      std::string group() const override
-         {
-         return "codec";
-         }
-
-      std::string description() const override
-         {
-         return "Hex encode a given file";
-         }
-
-      void go() override
-         {
-         auto hex_enc_f = [&](const uint8_t b[], size_t l) { output() << Botan::hex_encode(b, l); };
-         this->read_file(get_arg("file"), hex_enc_f, 2);
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("hex_enc", Hex_Encode);
-
-class Hex_Decode final : public Command
-   {
-   public:
-      Hex_Decode() : Command("hex_dec file") {}
-
-      std::string group() const override
-         {
-         return "codec";
-         }
-
-      std::string description() const override
-         {
-         return "Hex decode a given file";
-         }
-
-      void go() override
-         {
-         auto hex_dec_f = [&](const uint8_t b[], size_t l)
-            {
-            std::vector<uint8_t> bin = Botan::hex_decode(reinterpret_cast<const char*>(b), l);
-            output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
-            };
-
-         this->read_file(get_arg("file"), hex_dec_f, 2);
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("hex_dec", Hex_Decode);
-
-#endif
-
-#if defined(BOTAN_HAS_BASE64_CODEC)
-
-class Base64_Encode final : public Command
-   {
-   public:
-      Base64_Encode() : Command("base64_enc file") {}
-
-      std::string group() const override
-         {
-         return "codec";
-         }
-
-      std::string description() const override
-         {
-         return "Encode given file to Base64";
-         }
-
-      void go() override
-         {
-         auto onData = [&](const uint8_t b[], size_t l)
-            {
-            output() << Botan::base64_encode(b, l);
-            };
-         this->read_file(get_arg("file"), onData, 768);
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("base64_enc", Base64_Encode);
-
-class Base64_Decode final : public Command
-   {
-   public:
-      Base64_Decode() : Command("base64_dec file") {}
-
-      std::string group() const override
-         {
-         return "codec";
-         }
-
-      std::string description() const override
-         {
-         return "Decode Base64 encoded file";
-         }
-
-      void go() override
-         {
-         auto write_bin = [&](const uint8_t b[], size_t l)
-            {
-            Botan::secure_vector<uint8_t> bin = Botan::base64_decode(reinterpret_cast<const char*>(b), l);
-            output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
-            };
-
-         this->read_file(get_arg("file"), write_bin, 1024);
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("base64_dec", Base64_Decode);
-
-#endif // base64
-
-#if defined(BOTAN_HAS_HMAC)
-
-class HMAC final : public Command
-   {
-   public:
-      HMAC() : Command("hmac --hash=SHA-256 --buf-size=4096 --no-fsname key *files") {}
-
-      std::string group() const override
-         {
-         return "hmac";
-         }
-
-      std::string description() const override
-         {
-         return "Compute the HMAC tag of given file(s)";
-         }
-
-      void go() override
-         {
-         const bool no_fsname = flag_set("no-fsname");
-         const std::string hash_algo = get_arg("hash");
-         std::unique_ptr<Botan::MessageAuthenticationCode> hmac =
-            Botan::MessageAuthenticationCode::create("HMAC(" + hash_algo + ")");
-
-         if(!hmac)
-            { throw CLI_Error_Unsupported("HMAC", hash_algo); }
-
-         hmac->set_key(slurp_file(get_arg("key")));
-
-         const size_t buf_size = get_arg_sz("buf-size");
-
-         std::vector<std::string> files = get_arg_list("files");
-         if(files.empty())
-            { files.push_back("-"); } // read stdin if no arguments on command line
-
-         for(const std::string& fsname : files)
-            {
-            try
-               {
-               auto update_hmac = [&](const uint8_t b[], size_t l) { hmac->update(b, l); };
-               read_file(fsname, update_hmac, buf_size);
-               output() << Botan::hex_encode(hmac->final());
-
-               if(no_fsname == false)
-                  output() << " " << fsname;
-
-               output() << "\n";
-               }
-            catch(CLI_IO_Error& e)
-               {
-               error_output() << e.what() << "\n";
-               }
-            }
-         }
-   };
-
-BOTAN_REGISTER_COMMAND("hmac", HMAC);
-
-#endif // hmac
-
 }
diff --git a/src/lib/codec/base58/base58.cpp b/src/lib/codec/base58/base58.cpp
index ba974f96a..5aa9441d3 100644
--- a/src/lib/codec/base58/base58.cpp
+++ b/src/lib/codec/base58/base58.cpp
@@ -27,9 +27,7 @@ uint32_t sha256_d_checksum(const uint8_t input[], size_t input_length)
    sha256->update(checksum);
    sha256->final(checksum);
 
-   checksum.resize(4);
-   uint32_t c = load_be<uint32_t>(checksum.data(), 0);
-   return c;
+   return load_be<uint32_t>(checksum.data(), 0);
    }
 
 class Character_Table
@@ -140,7 +138,12 @@ std::vector<uint8_t> base58_decode(const char input[], size_t input_length)
 
    for(size_t i = leading_zeros; i != input_length; ++i)
       {
-      size_t idx = base58.code_for(input[i]);
+      const char c = input[i];
+
+      if(c == ' ' || c == '\n')
+         continue;
+
+      const size_t idx = base58.code_for(c);
 
       if(idx == 0x80)
          throw Decoding_Error("Invalid base58");


Test patch:
diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py
index f63b9dad9..d09ecf611 100755
--- a/src/scripts/test_cli.py
+++ b/src/scripts/test_cli.py
@@ -150,6 +150,13 @@ def cli_base64_tests():
     test_cli("base64_enc", "-", "YmVlcyE=", "bees!")
     test_cli("base64_dec", "-", "bees!", "YmVlcyE=")
 
+def cli_base58_tests():
+    test_cli("base58_enc", "-", "C6sRAr4", "bees!")
+    test_cli("base58_dec", "-", "bees!", "C6sRAr4")
+
+    test_cli("base58_enc", ["--check", "-"], "Cjv15cdjaBc", "F00F")
+    test_cli("base58_dec", ["--check", "-"], "F00F", "Cjv15cdjaBc")
+
 def cli_hex_tests():
     test_cli("hex_enc", "-", "6265657321", "bees!")
     test_cli("hex_dec", "-", "bees!", "6265657321")
@@ -750,6 +757,7 @@ def main(args=None):
     test_fns = [
         cli_asn1_tests,
         cli_asn1_tests,
+        cli_base58_tests,
         cli_base64_tests,
         cli_bcrypt_tests,
         cli_cc_enc_tests,