aboutsummaryrefslogtreecommitdiffstats
path: root/src/cli/pubkey.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/pubkey.cpp')
-rw-r--r--src/cli/pubkey.cpp278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/cli/pubkey.cpp b/src/cli/pubkey.cpp
new file mode 100644
index 000000000..35d50592f
--- /dev/null
+++ b/src/cli/pubkey.cpp
@@ -0,0 +1,278 @@
+/*
+* (C) 2010,2014,2015 Jack Lloyd
+* (C) 2015 René Korthaus
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
+
+#include <botan/auto_rng.h>
+#include <botan/base64.h>
+
+#include <botan/pk_keys.h>
+#include <botan/pkcs8.h>
+#include <botan/pubkey.h>
+
+#if defined(BOTAN_HAS_DL_GROUP)
+ #include <botan/dl_group.h>
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_CURVE_25519)
+ #include <botan/curve25519.h>
+#endif
+
+#if defined(BOTAN_HAS_MCELIECE)
+ #include <botan/mceliece.h>
+#endif
+
+namespace Botan_CLI {
+
+class PK_Keygen : public Command
+ {
+ public:
+ PK_Keygen() : Command("keygen --algo=RSA --params= --passphrase= --pbe= --pbe-millis=300") {}
+
+ std::unique_ptr<Botan::Private_Key> do_keygen(const std::string& algo,
+ const std::string& params,
+ Botan::RandomNumberGenerator& rng)
+ {
+ typedef std::function<std::unique_ptr<Botan::Private_Key> (std::string)> gen_fn;
+ std::map<std::string, gen_fn> generators;
+
+#if defined(BOTAN_HAS_RSA)
+ generators["RSA"] = [&rng](std::string param) -> std::unique_ptr<Botan::Private_Key> {
+ if(param.empty())
+ param = "2048";
+ return std::unique_ptr<Botan::Private_Key>(
+ new Botan::RSA_PrivateKey(rng, Botan::to_u32bit(param)));
+ };
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ generators["ECDSA"] = [&rng](std::string param) {
+ if(param.empty())
+ param = "secp256r1";
+ Botan::EC_Group grp(param);
+ return std::unique_ptr<Botan::Private_Key>(
+ new Botan::ECDSA_PrivateKey(rng, grp));
+ };
+#endif
+
+#if defined(BOTAN_HAS_CURVE_25519)
+ generators["Curve25519"] = [&rng](std::string /*ignored*/) {
+ return std::unique_ptr<Botan::Private_Key>(
+ new Botan::Curve25519_PrivateKey(rng));
+ };
+#endif
+
+#if defined(BOTAN_HAS_MCELIECE)
+ generators["McEliece"] = [&rng](std::string param) {
+ if(param.empty())
+ param = "2280,45";
+ std::vector<std::string> param_parts = Botan::split_on(param, ',');
+ if(param_parts.size() != 2)
+ throw CLI_Usage_Error("Bad McEliece parameters " + param);
+ return std::unique_ptr<Botan::Private_Key>(
+ new Botan::McEliece_PrivateKey(rng,
+ Botan::to_u32bit(param_parts[0]),
+ Botan::to_u32bit(param_parts[1])));
+ };
+#endif
+
+ auto gen = generators.find(algo);
+ if(gen == generators.end())
+ {
+ throw CLI_Error_Unsupported("keygen", algo);
+ }
+
+ return gen->second(params);
+ }
+
+ void go() override
+ {
+ Botan::AutoSeeded_RNG rng;
+ std::unique_ptr<Botan::Private_Key> key(do_keygen(get_arg("algo"), get_arg("params"), rng));
+
+ const std::string pass = get_arg("passphrase");
+
+ if(pass.empty())
+ {
+ output() << Botan::PKCS8::PEM_encode(*key);
+ }
+ else
+ {
+ output() << Botan::PKCS8::PEM_encode(*key,
+ rng,
+ pass,
+ std::chrono::milliseconds(get_arg_sz("pbe-millis")),
+ get_arg("pbe"));
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(PK_Keygen);
+
+namespace {
+
+std::string algo_default_emsa(const std::string& key)
+ {
+ if(key == "RSA")
+ return "EMSA4"; // PSS
+ else if(key == "ECDSA" || key == "DSA")
+ return "EMSA1";
+ else if(key == "RW")
+ return "EMSA2";
+ else
+ return "EMSA1";
+ }
+
+}
+
+class PK_Sign : public Command
+ {
+ public:
+ PK_Sign() : Command("sign --passphrase= --hash=SHA-256 --emsa= key file") {}
+
+ void go() override
+ {
+ Botan::AutoSeeded_RNG rng;
+
+ std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"),
+ rng,
+ get_arg("passphrase")));
+
+ if(!key)
+ throw CLI_Error("Unable to load private key");
+
+ const std::string sig_padding =
+ get_arg_or("emsa", algo_default_emsa(key->algo_name())) + "(" + get_arg("hash") + ")";
+
+ Botan::PK_Signer signer(*key, sig_padding);
+
+ this->read_file(get_arg("file"),
+ [&signer](const uint8_t b[], size_t l) { signer.update(b, l); });
+
+ output() << Botan::base64_encode(signer.signature(rng)) << "\n";
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(PK_Sign);
+
+class PK_Verify : public Command
+ {
+ public:
+ PK_Verify() : Command("verify --hash=SHA-256 --emsa= pubkey file signature") {}
+
+ void go() override
+ {
+ std::unique_ptr<Botan::Public_Key> key(Botan::X509::load_key(get_arg("pubkey")));
+ if(!key)
+ throw CLI_Error("Unable to load public key");
+
+ const std::string sig_padding =
+ get_arg_or("emsa", algo_default_emsa(key->algo_name())) + "(" + get_arg("hash") + ")";
+
+ Botan::PK_Verifier verifier(*key, sig_padding);
+ this->read_file(get_arg("file"),
+ [&verifier](const uint8_t b[], size_t l) { verifier.update(b, l); });
+
+ const Botan::secure_vector<uint8_t> signature =
+ Botan::base64_decode(this->slurp_file_as_str(get_arg("signature")));
+
+ const bool valid = verifier.check_signature(signature);
+
+ output() << "Signature is " << (valid ? "valid" : "invalid") << "\n";
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(PK_Verify);
+
+#if defined(BOTAN_HAS_DL_GROUP)
+
+class Gen_DL_Group : public Command
+ {
+ public:
+ Gen_DL_Group() : Command("gen_dl_group --pbits=1024 --qbits=0 --type=subgroup") {}
+
+ void go() override
+ {
+ Botan::AutoSeeded_RNG rng;
+
+ const size_t pbits = get_arg_sz("pbits");
+
+ const std::string type = get_arg("type");
+
+ if(type == "strong")
+ {
+ Botan::DL_Group grp(rng, Botan::DL_Group::Strong, pbits);
+ output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42);
+ }
+ else if(type == "subgroup")
+ {
+ Botan::DL_Group grp(rng, Botan::DL_Group::Prime_Subgroup, pbits, get_arg_sz("qbits"));
+ output() << grp.PEM_encode(Botan::DL_Group::ANSI_X9_42);
+ }
+ else
+ throw CLI_Usage_Error("Invalid DL type '" + type + "'");
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(Gen_DL_Group);
+
+#endif
+
+class PKCS8_Tool : public Command
+ {
+ public:
+ PKCS8_Tool() : Command("pkcs8 --pass-in= --pub-out --pass-out= --pbe= --pbe-millis=300 key") {}
+
+ void go() override
+ {
+ Botan::AutoSeeded_RNG rng;
+
+ std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"),
+ rng,
+ get_arg("pass-in")));
+
+ if(flag_set("pub-out"))
+ {
+ output() << Botan::X509::PEM_encode(*key);
+ }
+ else
+ {
+ const std::string pass = get_arg("pass-out");
+
+ if(pass.empty())
+ {
+ output() << Botan::PKCS8::PEM_encode(*key);
+ }
+ else
+ {
+ output() << Botan::PKCS8::PEM_encode(*key,
+ rng,
+ pass,
+ std::chrono::milliseconds(get_arg_sz("pbe-millis")),
+ get_arg("pbe"));
+ }
+
+ }
+
+ }
+ };
+
+BOTAN_REGISTER_COMMAND(PKCS8_Tool);
+
+}
+
+#endif