aboutsummaryrefslogtreecommitdiffstats
path: root/src/cli/encryption.cpp
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-12-12 13:21:43 +0100
committerSimon Warta <[email protected]>2017-04-18 09:37:41 +0200
commitfe6375e0f23757eb65c1ad491ab625afda0ee821 (patch)
treed1511d3429838398a06d6a91273bf77d42f5dfac /src/cli/encryption.cpp
parent3553ac7b22620604d19da4881201fb416425d23f (diff)
Add botan encryption cli app
Diffstat (limited to 'src/cli/encryption.cpp')
-rw-r--r--src/cli/encryption.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/cli/encryption.cpp b/src/cli/encryption.cpp
new file mode 100644
index 000000000..fa9a7e3df
--- /dev/null
+++ b/src/cli/encryption.cpp
@@ -0,0 +1,120 @@
+/*
+* (C) 2015 Simon Warta (Kullo GmbH)
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "apps.h"
+
+#if defined(BOTAN_HAS_AES)
+
+#include <botan/aes.h>
+#include <botan/aead.h>
+
+#include <iostream>
+#include <iterator>
+
+using namespace Botan;
+
+namespace {
+
+auto VALID_MODES = std::map<std::string, std::string>{
+ // Don't add algorithms here without extending tests
+ // in `src/scripts/cli_tests.py`
+ { "aes-128-gcm", "AES-128/GCM" },
+ { "aes-192-gcm", "AES-192/GCM" },
+ { "aes-256-gcm", "AES-256/GCM" },
+};
+
+secure_vector<byte> do_crypt(const std::string &cipher,
+ const secure_vector<byte> &input,
+ const SymmetricKey &key,
+ const InitializationVector &iv,
+ const OctetString &ad,
+ Cipher_Dir direction)
+ {
+ if (iv.size() == 0) throw std::invalid_argument("IV must not be empty");
+
+ // TODO: implement streaming
+
+ std::shared_ptr<Botan::Cipher_Mode> processor(Botan::get_cipher_mode(cipher, direction));
+ if(!processor) throw std::runtime_error("Cipher algorithm not found");
+
+ // Set key
+ processor->set_key(key);
+
+ // Set associated data
+ if (cipher.find("/GCM") != std::string::npos)
+ {
+ auto aead_processor = std::dynamic_pointer_cast<AEAD_Mode>(processor);
+ if(!aead_processor) throw std::runtime_error("Cipher algorithm not could not be converted to AEAD");
+ aead_processor->set_ad(ad.bits_of());
+ }
+
+ // Set IV
+ processor->start(iv.bits_of());
+
+ secure_vector<byte> buf(input.begin(), input.end());
+ processor->finish(buf);
+
+ return buf;
+ }
+
+secure_vector<byte> get_stdin()
+ {
+ secure_vector<byte> out;
+ std::streamsize reserved_size = 1048576; // 1 MiB
+ out.reserve(reserved_size);
+
+ std::istreambuf_iterator<char> iterator(std::cin.rdbuf()); // stdin iterator
+ std::istreambuf_iterator<char> EOS; // end-of-range iterator
+ std::copy(iterator, EOS, std::back_inserter(out));
+ return out;
+ }
+
+void to_stdout(const secure_vector<byte> &data)
+ {
+ std::copy(data.begin(), data.end(), std::ostreambuf_iterator<char>(std::cout));
+ }
+
+int encryption(const std::vector<std::string> &args)
+ {
+ OptionParser opts("debug|decrypt|mode=|key=|iv=|ad=");
+ opts.parse(args);
+
+ std::string mode = opts.value_if_set("mode");
+ if (!VALID_MODES.count(mode))
+ {
+ std::cout << "Invalid mode: '" << mode << "'\n"
+ << "valid modes are:";
+ for (auto valid_mode : VALID_MODES) std::cout << " " << valid_mode.first;
+ std::cout << std::endl;
+ return 1;
+ }
+
+ std::string key_hex = opts.value("key");
+ std::string iv_hex = opts.value("iv");
+ std::string ad_hex = opts.value_or_else("ad", "");
+
+ auto input = get_stdin();
+ if (opts.is_set("debug"))
+ {
+ std::cerr << "Got " << input.size() << " bytes of input data." << std::endl;
+ }
+
+ auto key = SymmetricKey(key_hex);
+ auto iv = InitializationVector(iv_hex);
+ auto ad = OctetString(ad_hex);
+
+ auto direction = opts.is_set("decrypt") ? Cipher_Dir::DECRYPTION : Cipher_Dir::ENCRYPTION;
+ auto out = do_crypt(VALID_MODES[mode], input, key, iv, ad, direction);
+ to_stdout(out);
+
+ return 0;
+ }
+
+}
+
+REGISTER_APP(encryption);
+
+#endif