aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aesxx
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2019-12-21 14:50:03 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2019-12-21 14:52:12 +0300
commit3304264990b96c09b174716ecb8da63d24457ae8 (patch)
tree9ec5711da75d4aa67587a8e39c24daaf6088c498 /aesxx
parenttest: move data files to test/data (diff)
downloadaes-tools-3304264990b96c09b174716ecb8da63d24457ae8.tar.gz
aes-tools-3304264990b96c09b174716ecb8da63d24457ae8.zip
utils/ -> aesxx/utils/
Diffstat (limited to 'aesxx')
-rw-r--r--aesxx/CMakeLists.txt2
-rw-r--r--aesxx/utils/CMakeLists.txt27
-rw-r--r--aesxx/utils/README.md158
-rw-r--r--aesxx/utils/block_cmd_parser.hpp124
-rw-r--r--aesxx/utils/block_dumper.hpp105
-rw-r--r--aesxx/utils/block_input.hpp29
-rw-r--r--aesxx/utils/bmp/butterfly.bmpbin0 -> 503370 bytes
-rw-r--r--aesxx/utils/bmp/cipherfly_cbc.bmpbin0 -> 503382 bytes
-rw-r--r--aesxx/utils/bmp/cipherfly_ecb.bmpbin0 -> 503382 bytes
-rw-r--r--aesxx/utils/data_parsers.hpp59
-rw-r--r--aesxx/utils/decrypt_block.cpp215
-rw-r--r--aesxx/utils/decrypt_bmp.cpp93
-rw-r--r--aesxx/utils/decrypt_file.cpp91
-rw-r--r--aesxx/utils/encrypt_block.cpp215
-rw-r--r--aesxx/utils/encrypt_bmp.cpp91
-rw-r--r--aesxx/utils/encrypt_file.cpp91
-rw-r--r--aesxx/utils/file_cmd_parser.hpp83
-rw-r--r--aesxx/utils/helpers/bmp.hpp57
-rw-r--r--aesxx/utils/helpers/command_line.hpp87
-rw-r--r--aesxx/utils/helpers/file.hpp69
20 files changed, 1596 insertions, 0 deletions
diff --git a/aesxx/CMakeLists.txt b/aesxx/CMakeLists.txt
index 9bbf777..7f5a58a 100644
--- a/aesxx/CMakeLists.txt
+++ b/aesxx/CMakeLists.txt
@@ -11,3 +11,5 @@ if(MSVC_VERSION EQUAL 1900)
endif()
install(DIRECTORY include/aesxx DESTINATION include)
+
+add_subdirectory(utils)
diff --git a/aesxx/utils/CMakeLists.txt b/aesxx/utils/CMakeLists.txt
new file mode 100644
index 0000000..27d3422
--- /dev/null
+++ b/aesxx/utils/CMakeLists.txt
@@ -0,0 +1,27 @@
+find_package(Boost REQUIRED COMPONENTS filesystem program_options)
+
+function(add_util name src)
+ set(target "util_${name}")
+ add_executable("${target}" ${src})
+ target_link_libraries("${target}" PRIVATE aesxx Boost::filesystem Boost::program_options)
+ set_target_properties("${target}" PROPERTIES OUTPUT_NAME "${name}")
+ install(TARGETS "${target}" RUNTIME DESTINATION bin)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ install(FILES "$<TARGET_PDB_FILE:${target}>" DESTINATION bin OPTIONAL)
+ endif()
+endfunction()
+
+set(block_util_headers block_cmd_parser.hpp block_dumper.hpp block_input.hpp data_parsers.hpp helpers/command_line.hpp)
+
+add_util(encrypt_block encrypt_block.cpp ${block_util_headers})
+add_util(decrypt_block decrypt_block.cpp ${block_util_headers})
+
+set(file_util_headers data_parsers.hpp file_cmd_parser.hpp helpers/command_line.hpp helpers/file.hpp)
+
+add_util(encrypt_file encrypt_file.cpp ${file_util_headers})
+add_util(decrypt_file decrypt_file.cpp ${file_util_headers})
+
+set(bmp_util_headers ${file_util_headers} helpers/bmp.hpp)
+
+add_util(encrypt_bmp encrypt_bmp.cpp ${bmp_util_headers})
+add_util(decrypt_bmp decrypt_bmp.cpp ${bmp_util_headers})
diff --git a/aesxx/utils/README.md b/aesxx/utils/README.md
new file mode 100644
index 0000000..c133c92
--- /dev/null
+++ b/aesxx/utils/README.md
@@ -0,0 +1,158 @@
+Utilities
+=========
+
+A couple of useful utilities are built on top of the library.
+Each of the utilities accepts the `--help` flag, which can be used to examine
+utility's detailed usage information.
+
+Block encryption
+----------------
+
+Block encryption utilities can produce verbose human-readable output, including
+round keys, intermediate initialization vector values, etc.
+They are primarily intended for debugging purposes.
+Enable verbose output by passing the `--verbose` flag.
+Please note that verbose output can only be produced when *not* using the
+"boxes" interface (the `--use-boxes` flag).
+
+### encrypt_block
+
+Encrypts blocks using the selected algorithm in the specified mode of
+operation.
+
+For example, to encrypt
+
+* the plaintext block `0x00112233445566778899aabbccddeeff`
+* using AES-128 in ECB mode
+* with key `0x000102030405060708090a0b0c0d0e0f`,
+
+run:
+
+ encrypt_block -a aes128 -m ecb 000102030405060708090a0b0c0d0e0f 00112233445566778899aabbccddeeff
+
+To encrypt
+
+* the plaintext block `0x00112233445566778899aabbccddeeff`
+* using AES-192 in OFB mode
+* with initialization vector `0x22222222222222222222222222222222`
+* and key `0x000102030405060708090a0b0c0d0e0f101112131415161718`,
+
+run:
+
+ encrypt_block -a aes192 -m ofb 000102030405060708090a0b0c0d0e0f101112131415161718 22222222222222222222222222222222 00112233445566778899aabbccddeeff
+
+### decrypt_block
+
+Decrypts blocks using the selected algorithm in the specified mode of
+operation.
+
+For example, to decrypt
+
+* the ciphertext block `0x69c4e0d86a7b0430d8cdb78070b4c55a`
+* using AES-128 in ECB mode
+* with key `0x000102030405060708090a0b0c0d0e0f`,
+
+run:
+
+ decrypt_block -a aes128 -m ecb 000102030405060708090a0b0c0d0e0f 69c4e0d86a7b0430d8cdb78070b4c55a
+
+To decrypt
+
+* the ciphertext block `0x762a5ab50929189cefdb99434790aad8`
+* using AES-192 in OFB mode
+* with initialization vector `0x22222222222222222222222222222222`
+* and key `0x000102030405060708090a0b0c0d0e0f101112131415161718`,
+
+run:
+
+ decrypt_block -a aes192 -m ofb 000102030405060708090a0b0c0d0e0f101112131415161718 22222222222222222222222222222222 bda298884f5c3a9eb7068aa7063a3b75
+
+File encryption
+---------------
+
+### encrypt_file
+
+Encrypts a file using the selected algorithm in the specified mode of
+operation.
+
+For example, to encrypt the plaintext from "input.txt"
+
+* using AES-128 in ECB mode
+* with key `0x11111111111111111111111111111111`
+* and write the ciphertext to "output.txt",
+
+run:
+
+ encrypt_file -a aes128 -m ecb -k 11111111111111111111111111111111 -i input.txt -o output.txt
+
+To encrypt the plaintext from "input.txt"
+
+* using AES-192 in OFB mode
+* with key `0x111111111111111111111111111111111111111111111111`
+* and initialization vector `0x22222222222222222222222222222222`
+* and write the ciphertext to "output.txt":
+
+run
+
+ encrypt_file -a aes192 -m ofb -k 111111111111111111111111111111111111111111111111 -v 22222222222222222222222222222222 -i input.txt -o output.txt
+
+### decrypt_file
+
+Decrypts a file using the selected algorithm in the specified mode of
+operation.
+
+To decrypt the ciphertext from "input.txt"
+
+* using AES-128 in ECB mode
+* with key `0x11111111111111111111111111111111`
+* and write the plaintext to "output.txt",
+
+run
+
+ decrypt_file -a aes128 -m ecb -k 11111111111111111111111111111111 -i input.txt -o output.txt
+
+To decrypt the ciphertext from "input.txt"
+
+* using AES-192 in OFB mode
+* with key `0x111111111111111111111111111111111111111111111111`
+* and initialization vector `0x22222222222222222222222222222222`
+* and write the plaintext to "output.txt",
+
+run
+
+ decrypt_file -a aes192 -m ofb -k 111111111111111111111111111111111111111111111111 -v 22222222222222222222222222222222 -i input.txt -o output.txt
+
+Bitmap encryption
+-----------------
+
+These utilities were developed primarily to demonstrate the drawbacks of using
+ECB mode (namely, the fact that identical plaintext blocks get mapped to
+identical ciphertext blocks).
+This can be explicitly shown using 8-bit-per-pixel bitmaps:
+
+| Plaintext BMP | Encrypted in ECB mode | Encrypted in CBC mode
+| ---------------- | --------------------- | ---------------------
+| ![butterfly.bmp] | ![cipherfly_ecb.bmp] | ![cipherfly_cbc.bmp]
+
+[butterfly.bmp]: bmp/butterfly.bmp
+[cipherfly_ecb.bmp]: bmp/cipherfly_ecb.bmp
+[cipherfly_cbc.bmp]: bmp/cipherfly_cbc.bmp
+
+### encrypt_bmp
+
+Encrypts the pixels in a BMP image file, preserving the header.
+Otherwise, it's used the same way [encrypt_file](#encrypt_file) is.
+
+### decrypt_bmp
+
+Decrypts the pixels in a BMP image file, preserving the header.
+Otherwise, it's used the same way [decrypt_file](#decrypt_file) is.
+
+See also
+--------
+
+* [Usage on older CPUs]
+* [License]
+
+[Usage on older CPUs]: ../../README.md#usage-on-older-cpus
+[License]: ../../README.md#license
diff --git a/aesxx/utils/block_cmd_parser.hpp b/aesxx/utils/block_cmd_parser.hpp
new file mode 100644
index 0000000..58f86d8
--- /dev/null
+++ b/aesxx/utils/block_cmd_parser.hpp
@@ -0,0 +1,124 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "block_input.hpp"
+#include "data_parsers.hpp"
+#include "helpers/command_line.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <deque>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+class BlockSettings : public command_line::SettingsParser
+{
+public:
+ aes::Algorithm algorithm = AES_AES128;
+ aes::Mode mode = AES_ECB;
+
+ bool use_boxes = false;
+ bool verbose = false;
+
+ std::vector<Input> inputs;
+
+ explicit BlockSettings(const std::string& argv0)
+ : SettingsParser{argv0}
+ {
+ visible.add_options()
+ ("verbose,v",
+ boost::program_options::bool_switch(&verbose),
+ "enable verbose output")
+ ("algorithm,a",
+ boost::program_options::value<aes::Algorithm>(&algorithm)
+ ->required()
+ ->value_name("NAME"),
+ "set algorithm")
+ ("mode,m",
+ boost::program_options::value<aes::Mode>(&mode)
+ ->required()
+ ->value_name("MODE"),
+ "set mode of operation")
+ ("use-boxes,b",
+ boost::program_options::bool_switch(&use_boxes),
+ "use the \"boxes\" interface");
+ hidden.add_options()
+ ("args",
+ boost::program_options::value<std::vector<std::string>>(&args),
+ "shouldn't be visible");
+ positional.add("args", -1);
+ }
+
+ const char* get_short_description() const override
+ {
+ return "[-h|--help] [-v|--verbose] [-a|--algorithm NAME] [-m|--mode MODE]"
+ " [-- KEY [IV] [BLOCK]...]...";
+ }
+
+ void parse(int argc, char* argv[]) override
+ {
+ SettingsParser::parse(argc, argv);
+ parse_inputs(std::deque<std::string>{
+ std::make_move_iterator(args.begin()),
+ std::make_move_iterator(args.end())});
+ }
+
+private:
+ void parse_inputs(std::deque<std::string>&& src)
+ {
+ while (!src.empty())
+ inputs.emplace_back(parse_input(src));
+ }
+
+ Input parse_input(std::deque<std::string>& src) const
+ {
+ std::string key{std::move(src.front())};
+ src.pop_front();
+
+ std::string iv;
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ if (src.empty())
+ {
+ throw boost::program_options::error{
+ "an initialization vector is required for the selected mode of operation"};
+ }
+ iv = std::move(src.front());
+ src.pop_front();
+ }
+
+ auto blocks = parse_blocks(src);
+
+ if (aes::mode_requires_init_vector(mode))
+ return {key, iv, std::move(blocks)};
+ else
+ return {key, std::move(blocks)};
+ }
+
+ static std::vector<std::string> parse_blocks(std::deque<std::string>& src)
+ {
+ std::vector<std::string> blocks;
+
+ while (!src.empty())
+ {
+ std::string block{std::move(src.front())};
+ src.pop_front();
+ if (block == "--")
+ break;
+ blocks.emplace_back(std::move(block));
+ }
+
+ return blocks;
+ }
+
+ std::vector<std::string> args;
+};
diff --git a/aesxx/utils/block_dumper.hpp b/aesxx/utils/block_dumper.hpp
new file mode 100644
index 0000000..a07d855
--- /dev/null
+++ b/aesxx/utils/block_dumper.hpp
@@ -0,0 +1,105 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <aesxx/all.hpp>
+
+#include <cstdlib>
+
+#include <iostream>
+#include <type_traits>
+
+template <aes::Algorithm algorithm>
+void dump_block(
+ const char* header,
+ const typename aes::Types<algorithm>::Block& block)
+{
+ std::cout << header << ": " << aes::to_string<algorithm>(block) << "\n";
+ std::cout << aes::to_matrix_string<algorithm>(block) << "\n";
+}
+
+template <aes::Algorithm algorithm>
+void dump_plaintext(const typename aes::Types<algorithm>::Block& block)
+{
+ dump_block<algorithm>("Plaintext", block);
+}
+
+template <aes::Algorithm algorithm>
+void dump_key(const typename aes::Types<algorithm>::Key& key)
+{
+ std::cout << "Key: " << aes::to_string<algorithm>(key) << "\n\n";
+}
+
+template <aes::Algorithm algorithm>
+void dump_ciphertext(const typename aes::Types<algorithm>::Block& ciphertext)
+{
+ dump_block<algorithm>("Ciphertext", ciphertext);
+}
+
+template <aes::Algorithm algorithm>
+void dump_iv(const typename aes::Types<algorithm>::Block& iv)
+{
+ dump_block<algorithm>("Initialization vector", iv);
+}
+
+template <aes::Algorithm algorithm>
+void dump_round_keys(
+ const char* header,
+ const typename aes::Types<algorithm>::RoundKeys& round_keys)
+{
+ std::cout << header << ":\n";
+ for (std::size_t i = 0; i < aes::get_number_of_rounds<algorithm>(); ++i)
+ std::cout << "\t[" << i << "]: " << aes::to_string<algorithm>(round_keys.keys[i]) << "\n";
+ std::cout << "\n";
+}
+
+template <aes::Algorithm algorithm>
+void dump_encryption_keys(const typename aes::Types<algorithm>::RoundKeys& round_keys)
+{
+ dump_round_keys<algorithm>("Encryption round keys", round_keys);
+}
+
+template <aes::Algorithm algorithm>
+void dump_decryption_keys(const typename aes::Types<algorithm>::RoundKeys& round_keys)
+{
+ dump_round_keys<algorithm>("Decryption round keys", round_keys);
+}
+
+template <aes::Algorithm algorithm, aes::Mode mode>
+void dump_wrapper(const aes::EncryptWrapper<algorithm, mode>& wrapper)
+{
+ dump_encryption_keys<algorithm>(wrapper.encryption_keys);
+}
+
+template <aes::Algorithm algorithm, aes::Mode mode>
+void dump_wrapper(const aes::DecryptWrapper<algorithm, mode>& wrapper)
+{
+ dump_decryption_keys<algorithm>(wrapper.decryption_keys);
+}
+
+template <aes::Algorithm algorithm, aes::Mode mode,
+ typename std::enable_if<aes::ModeRequiresInitVector<mode>::value>::type* = nullptr>
+void dump_next_iv(const aes::EncryptWrapper<algorithm, mode>& wrapper)
+{
+ dump_block<algorithm>("Next initialization vector", wrapper.iv);
+}
+
+template <aes::Algorithm algorithm, aes::Mode mode,
+ typename std::enable_if<!aes::ModeRequiresInitVector<mode>::value>::type* = nullptr>
+void dump_next_iv(const aes::EncryptWrapper<algorithm, mode>&)
+{ }
+
+template <aes::Algorithm algorithm, aes::Mode mode,
+ typename std::enable_if<aes::ModeRequiresInitVector<mode>::value>::type* = nullptr>
+void dump_next_iv(const aes::DecryptWrapper<algorithm, mode>& wrapper)
+{
+ dump_block<algorithm>("Next initialization vector", wrapper.iv);
+}
+
+template <aes::Algorithm algorithm, aes::Mode mode,
+ typename std::enable_if<!aes::ModeRequiresInitVector<mode>::value>::type* = nullptr>
+void dump_next_iv(const aes::DecryptWrapper<algorithm, mode>&)
+{ }
diff --git a/aesxx/utils/block_input.hpp b/aesxx/utils/block_input.hpp
new file mode 100644
index 0000000..f629062
--- /dev/null
+++ b/aesxx/utils/block_input.hpp
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+
+class Input
+{
+public:
+ Input(const std::string& key, const std::string& iv, std::vector<std::string>&& blocks)
+ : key{key}
+ , iv{iv}
+ , blocks{std::move(blocks)}
+ { }
+
+ Input(const std::string& key, std::vector<std::string>&& blocks)
+ : key{key}
+ , blocks{std::move(blocks)}
+ { }
+
+ const std::string key;
+ const std::string iv;
+ const std::vector<std::string> blocks;
+};
diff --git a/aesxx/utils/bmp/butterfly.bmp b/aesxx/utils/bmp/butterfly.bmp
new file mode 100644
index 0000000..105a55a
--- /dev/null
+++ b/aesxx/utils/bmp/butterfly.bmp
Binary files differ
diff --git a/aesxx/utils/bmp/cipherfly_cbc.bmp b/aesxx/utils/bmp/cipherfly_cbc.bmp
new file mode 100644
index 0000000..664b557
--- /dev/null
+++ b/aesxx/utils/bmp/cipherfly_cbc.bmp
Binary files differ
diff --git a/aesxx/utils/bmp/cipherfly_ecb.bmp b/aesxx/utils/bmp/cipherfly_ecb.bmp
new file mode 100644
index 0000000..78de9a8
--- /dev/null
+++ b/aesxx/utils/bmp/cipherfly_ecb.bmp
Binary files differ
diff --git a/aesxx/utils/data_parsers.hpp b/aesxx/utils/data_parsers.hpp
new file mode 100644
index 0000000..1207c7c
--- /dev/null
+++ b/aesxx/utils/data_parsers.hpp
@@ -0,0 +1,59 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <aesxx/all.hpp>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/program_options.hpp>
+
+#include <istream>
+#include <string>
+#include <unordered_map>
+
+inline std::istream& operator>>(std::istream& is, aes::Mode& dest)
+{
+ std::string src;
+ is >> src;
+
+ static const std::unordered_map<std::string, aes::Mode> lookup_table =
+ {
+ {"ecb", AES_ECB},
+ {"cbc", AES_CBC},
+ {"cfb", AES_CFB},
+ {"ofb", AES_OFB},
+ {"ctr", AES_CTR},
+ };
+
+ const auto it = lookup_table.find(boost::algorithm::to_lower_copy(src));
+
+ if (it == lookup_table.cend())
+ throw boost::program_options::invalid_option_value(src);
+
+ dest = it->second;
+ return is;
+}
+
+inline std::istream& operator>>(std::istream& is, aes::Algorithm& dest)
+{
+ std::string src;
+ is >> src;
+
+ static const std::unordered_map<std::string, aes::Algorithm> lookup_table =
+ {
+ {"aes128", AES_AES128},
+ {"aes192", AES_AES192},
+ {"aes256", AES_AES256},
+ };
+
+ const auto it = lookup_table.find(boost::algorithm::to_lower_copy(src));
+
+ if (it == lookup_table.cend())
+ throw boost::program_options::invalid_option_value(src);
+
+ dest = it->second;
+ return is;
+}
diff --git a/aesxx/utils/decrypt_block.cpp b/aesxx/utils/decrypt_block.cpp
new file mode 100644
index 0000000..02a3033
--- /dev/null
+++ b/aesxx/utils/decrypt_block.cpp
@@ -0,0 +1,215 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "block_cmd_parser.hpp"
+#include "block_dumper.hpp"
+#include "block_input.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+namespace
+{
+ template <aes::Algorithm algorithm, aes::Mode mode>
+ void decrypt_with_mode(
+ const Input& input,
+ bool verbose = false)
+ {
+ typename aes::Types<algorithm>::Block iv;
+
+ if (aes::ModeRequiresInitVector<mode>())
+ {
+ aes::from_string<algorithm>(iv, input.iv);
+ if (verbose)
+ dump_iv<algorithm>(iv);
+ }
+
+ typename aes::Types<algorithm>::Key key;
+ aes::from_string<algorithm>(key, input.key);
+ if (verbose)
+ dump_key<algorithm>(key);
+
+ aes::DecryptWrapper<algorithm, mode> decrypt{key, iv};
+ if (verbose)
+ dump_wrapper<algorithm, mode>(decrypt);
+
+ for (const auto& block : input.blocks)
+ {
+ typename aes::Types<algorithm>::Block ciphertext, plaintext;
+ aes::from_string<algorithm>(ciphertext, block);
+
+ decrypt.decrypt_block(ciphertext, plaintext);
+
+ if (verbose)
+ {
+ dump_ciphertext<algorithm>(ciphertext);
+ dump_plaintext<algorithm>(plaintext);
+ dump_next_iv<algorithm, mode>(decrypt);
+ }
+ else
+ {
+ std::cout << aes::to_string<algorithm>(plaintext) << '\n';
+ }
+ }
+ }
+
+ template <aes::Algorithm algorithm>
+ void decrypt_with_algorithm(
+ aes::Mode mode,
+ const Input& input,
+ bool verbose = false)
+ {
+ switch (mode)
+ {
+ case AES_ECB:
+ decrypt_with_mode<algorithm, AES_ECB>(input, verbose);
+ break;
+
+ case AES_CBC:
+ decrypt_with_mode<algorithm, AES_CBC>(input, verbose);
+ break;
+
+ case AES_CFB:
+ decrypt_with_mode<algorithm, AES_CFB>(input, verbose);
+ break;
+
+ case AES_OFB:
+ decrypt_with_mode<algorithm, AES_OFB>(input, verbose);
+ break;
+
+ case AES_CTR:
+ decrypt_with_mode<algorithm, AES_CTR>(input, verbose);
+ break;
+
+ default:
+ throw std::runtime_error("the selected mode of operation is not implemented");
+ break;
+ }
+ }
+
+ void decrypt_using_cxx_api(
+ aes::Algorithm algorithm,
+ aes::Mode mode,
+ const Input& input,
+ bool verbose = false)
+ {
+ switch (algorithm)
+ {
+ case AES_AES128:
+ decrypt_with_algorithm<AES_AES128>(mode, input, verbose);
+ break;
+
+ case AES_AES192:
+ decrypt_with_algorithm<AES_AES192>(mode, input, verbose);
+ break;
+
+ case AES_AES256:
+ decrypt_with_algorithm<AES_AES256>(mode, input, verbose);
+ break;
+
+ default:
+ throw std::runtime_error("the selected algorithm is not implemented");
+ break;
+ }
+ }
+
+ void decrypt_using_particular_box(
+ aes::Box& box,
+ const std::vector<std::string>& blocks)
+ {
+ for (const auto& block : blocks)
+ {
+ aes::Box::Block ciphertext;
+ box.parse_block(ciphertext, block);
+
+ aes::Box::Block plaintext;
+ box.decrypt_block(ciphertext, plaintext);
+ std::cout << box.format_block(plaintext) << '\n';
+ }
+ }
+
+ void decrypt_using_boxes(
+ aes::Algorithm algorithm,
+ aes::Mode mode,
+ const Input& input)
+ {
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, input.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, input.iv);
+ aes::Box box{algorithm, key, mode, iv};
+
+ decrypt_using_particular_box(box, input.blocks);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ decrypt_using_particular_box(box, input.blocks);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ BlockSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ for (const auto& input : settings.inputs)
+ {
+ if (settings.use_boxes)
+ {
+ decrypt_using_boxes(
+ settings.algorithm,
+ settings.mode,
+ input);
+ }
+ else
+ {
+ decrypt_using_cxx_api(
+ settings.algorithm,
+ settings.mode,
+ input,
+ settings.verbose);
+ }
+ }
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/decrypt_bmp.cpp b/aesxx/utils/decrypt_bmp.cpp
new file mode 100644
index 0000000..9f9cd52
--- /dev/null
+++ b/aesxx/utils/decrypt_bmp.cpp
@@ -0,0 +1,93 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "file_cmd_parser.hpp"
+#include "helpers/bmp.hpp"
+#include "helpers/file.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <windows.h>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+
+namespace
+{
+ void decrypt_bmp(
+ aes::Box& box,
+ const std::string& ciphertext_path,
+ const std::string& plaintext_path)
+ {
+ bmp::BmpFile bmp{file::read_file(ciphertext_path)};
+ bmp.replace_pixels(box.decrypt_buffer(
+ bmp.get_pixels(),
+ bmp.get_pixels_size()));
+ file::write_file(plaintext_path, bmp.get_buffer(), bmp.get_size());
+ }
+
+ void decrypt_bmp(const FileSettings& settings)
+ {
+ const auto& algorithm = settings.algorithm;
+ const auto& mode = settings.mode;
+
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, settings.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, settings.iv);
+
+ aes::Box box{algorithm, key, mode, iv};
+ decrypt_bmp(box, settings.input_path, settings.output_path);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ decrypt_bmp(box, settings.input_path, settings.output_path);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ FileSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ decrypt_bmp(settings);
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/decrypt_file.cpp b/aesxx/utils/decrypt_file.cpp
new file mode 100644
index 0000000..6da3d17
--- /dev/null
+++ b/aesxx/utils/decrypt_file.cpp
@@ -0,0 +1,91 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "file_cmd_parser.hpp"
+#include "helpers/file.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace
+{
+ void decrypt_file(
+ aes::Box& box,
+ const std::string& ciphertext_path,
+ const std::string& plaintext_path)
+ {
+ const auto ciphertext_buf = file::read_file(ciphertext_path);
+ const auto plaintext_buf = box.decrypt_buffer(
+ ciphertext_buf.data(),
+ ciphertext_buf.size());
+ file::write_file(plaintext_path, plaintext_buf);
+ }
+
+ void decrypt_file(const FileSettings& settings)
+ {
+ const auto& algorithm = settings.algorithm;
+ const auto& mode = settings.mode;
+
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, settings.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, settings.iv);
+
+ aes::Box box{algorithm, key, mode, iv};
+ decrypt_file(box, settings.input_path, settings.output_path);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ decrypt_file(box, settings.input_path, settings.output_path);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ FileSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ decrypt_file(settings);
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/encrypt_block.cpp b/aesxx/utils/encrypt_block.cpp
new file mode 100644
index 0000000..0b87364
--- /dev/null
+++ b/aesxx/utils/encrypt_block.cpp
@@ -0,0 +1,215 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "block_cmd_parser.hpp"
+#include "block_dumper.hpp"
+#include "block_input.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+namespace
+{
+ template <aes::Algorithm algorithm, aes::Mode mode>
+ void encrypt_with_mode(
+ const Input& input,
+ bool verbose = false)
+ {
+ typename aes::Types<algorithm>::Block iv;
+
+ if (aes::ModeRequiresInitVector<mode>::value)
+ {
+ aes::from_string<algorithm>(iv, input.iv);
+ if (verbose)
+ dump_iv<algorithm>(iv);
+ }
+
+ typename aes::Types<algorithm>::Key key;
+ aes::from_string<algorithm>(key, input.key);
+ if (verbose)
+ dump_key<algorithm>(key);
+
+ aes::EncryptWrapper<algorithm, mode> encrypt{key, iv};
+ if (verbose)
+ dump_wrapper<algorithm, mode>(encrypt);
+
+ for (const auto& input_block_string : input.blocks)
+ {
+ typename aes::Types<algorithm>::Block plaintext, ciphertext;
+ aes::from_string<algorithm>(plaintext, input_block_string);
+
+ encrypt.encrypt_block(plaintext, ciphertext);
+
+ if (verbose)
+ {
+ dump_plaintext<algorithm>(plaintext);
+ dump_ciphertext<algorithm>(ciphertext);
+ dump_next_iv<algorithm, mode>(encrypt);
+ }
+ else
+ {
+ std::cout << aes::to_string<algorithm>(ciphertext) << '\n';
+ }
+ }
+ }
+
+ template <aes::Algorithm algorithm>
+ void encrypt_with_algorithm(
+ aes::Mode mode,
+ const Input& input,
+ bool verbose = false)
+ {
+ switch (mode)
+ {
+ case AES_ECB:
+ encrypt_with_mode<algorithm, AES_ECB>(input, verbose);
+ break;
+
+ case AES_CBC:
+ encrypt_with_mode<algorithm, AES_CBC>(input, verbose);
+ break;
+
+ case AES_CFB:
+ encrypt_with_mode<algorithm, AES_CFB>(input, verbose);
+ break;
+
+ case AES_OFB:
+ encrypt_with_mode<algorithm, AES_OFB>(input, verbose);
+ break;
+
+ case AES_CTR:
+ encrypt_with_mode<algorithm, AES_CTR>(input, verbose);
+ break;
+
+ default:
+ throw std::runtime_error("the selected mode of operation is not implemented");
+ break;
+ }
+ }
+
+ void encrypt_using_cxx_api(
+ aes::Algorithm algorithm,
+ aes::Mode mode,
+ const Input& input,
+ bool verbose = false)
+ {
+ switch (algorithm)
+ {
+ case AES_AES128:
+ encrypt_with_algorithm<AES_AES128>(mode, input, verbose);
+ break;
+
+ case AES_AES192:
+ encrypt_with_algorithm<AES_AES192>(mode, input, verbose);
+ break;
+
+ case AES_AES256:
+ encrypt_with_algorithm<AES_AES256>(mode, input, verbose);
+ break;
+
+ default:
+ throw std::runtime_error("the selected algorithm is not implemented");
+ break;
+ }
+ }
+
+ void encrypt_using_particular_box(
+ aes::Box& box,
+ const std::vector<std::string>& input_block_strings)
+ {
+ for (const auto& input_block_string : input_block_strings)
+ {
+ aes::Box::Block plaintext;
+ box.parse_block(plaintext, input_block_string);
+
+ aes::Box::Block ciphertext;
+ box.encrypt_block(plaintext, ciphertext);
+ std::cout << box.format_block(ciphertext) << '\n';
+ }
+ }
+
+ void encrypt_using_boxes(
+ aes::Algorithm algorithm,
+ aes::Mode mode,
+ const Input& input)
+ {
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, input.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, input.iv);
+ aes::Box box{algorithm, key, mode, iv};
+
+ encrypt_using_particular_box(box, input.blocks);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ encrypt_using_particular_box(box, input.blocks);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ BlockSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ for (const auto& input : settings.inputs)
+ {
+ if (settings.use_boxes)
+ {
+ encrypt_using_boxes(
+ settings.algorithm,
+ settings.mode,
+ input);
+ }
+ else
+ {
+ encrypt_using_cxx_api(
+ settings.algorithm,
+ settings.mode,
+ input,
+ settings.verbose);
+ }
+ }
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/encrypt_bmp.cpp b/aesxx/utils/encrypt_bmp.cpp
new file mode 100644
index 0000000..7f1a890
--- /dev/null
+++ b/aesxx/utils/encrypt_bmp.cpp
@@ -0,0 +1,91 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "file_cmd_parser.hpp"
+#include "helpers/bmp.hpp"
+#include "helpers/file.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+
+namespace
+{
+ void encrypt_bmp(
+ aes::Box& box,
+ const std::string& plaintext_path,
+ const std::string& ciphertext_path)
+ {
+ bmp::BmpFile bmp{file::read_file(plaintext_path)};
+ bmp.replace_pixels(box.encrypt_buffer(
+ bmp.get_pixels(),
+ bmp.get_pixels_size()));
+ file::write_file(ciphertext_path, bmp.get_buffer(), bmp.get_size());
+ }
+
+ void encrypt_bmp(const FileSettings& settings)
+ {
+ const auto& algorithm = settings.algorithm;
+ const auto& mode = settings.mode;
+
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, settings.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, settings.iv);
+
+ aes::Box box{algorithm, key, mode, iv};
+ encrypt_bmp(box, settings.input_path, settings.output_path);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ encrypt_bmp(box, settings.input_path, settings.output_path);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ FileSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ encrypt_bmp(settings);
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/encrypt_file.cpp b/aesxx/utils/encrypt_file.cpp
new file mode 100644
index 0000000..570bc60
--- /dev/null
+++ b/aesxx/utils/encrypt_file.cpp
@@ -0,0 +1,91 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include "file_cmd_parser.hpp"
+#include "helpers/file.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace
+{
+ void encrypt_file(
+ aes::Box& box,
+ const std::string& plaintext_path,
+ const std::string& ciphertext_path)
+ {
+ const auto plaintext_buf = file::read_file(plaintext_path);
+ const auto ciphertext_buf = box.encrypt_buffer(
+ plaintext_buf.data(),
+ plaintext_buf.size());
+ file::write_file(ciphertext_path, ciphertext_buf);
+ }
+
+ void encrypt_file(const FileSettings& settings)
+ {
+ const auto& algorithm = settings.algorithm;
+ const auto& mode = settings.mode;
+
+ aes::Box::Key key;
+ aes::Box::parse_key(key, algorithm, settings.key);
+
+ if (aes::mode_requires_init_vector(mode))
+ {
+ aes::Box::Block iv;
+ aes::Box::parse_block(iv, algorithm, settings.iv);
+
+ aes::Box box{algorithm, key, mode, iv};
+ encrypt_file(box, settings.input_path, settings.output_path);
+ }
+ else
+ {
+ aes::Box box{algorithm, key};
+ encrypt_file(box, settings.input_path, settings.output_path);
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ try
+ {
+ FileSettings settings{argv[0]};
+
+ try
+ {
+ settings.parse(argc, argv);
+ }
+ catch (const boost::program_options::error& e)
+ {
+ settings.usage_error(e);
+ return 1;
+ }
+
+ if (settings.exit_with_usage)
+ {
+ settings.usage();
+ return 0;
+ }
+
+ encrypt_file(settings);
+ }
+ catch (const aes::Error& e)
+ {
+ std::cerr << e;
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/aesxx/utils/file_cmd_parser.hpp b/aesxx/utils/file_cmd_parser.hpp
new file mode 100644
index 0000000..e199409
--- /dev/null
+++ b/aesxx/utils/file_cmd_parser.hpp
@@ -0,0 +1,83 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "data_parsers.hpp"
+#include "helpers/command_line.hpp"
+
+#include <aesxx/all.hpp>
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <ostream>
+#include <string>
+#include <utility>
+
+class FileSettings : public command_line::SettingsParser
+{
+public:
+ aes::Algorithm algorithm = AES_AES128;
+ aes::Mode mode = AES_ECB;
+
+ std::string input_path;
+ std::string output_path;
+ std::string key;
+ std::string iv;
+
+ explicit FileSettings(const std::string& argv0)
+ : SettingsParser{argv0}
+ {
+ visible.add_options()
+ ("algorithm,a",
+ boost::program_options::value<aes::Algorithm>(&algorithm)
+ ->required()
+ ->value_name("NAME"),
+ "set algorithm")
+ ("mode,m",
+ boost::program_options::value<aes::Mode>(&mode)
+ ->required()
+ ->value_name("MODE"),
+ "set mode of operation")
+ ("key,k",
+ boost::program_options::value<std::string>(&key)
+ ->required()
+ ->value_name("KEY"),
+ "set encryption key")
+ ("iv,v",
+ boost::program_options::value<std::string>(&iv)
+ ->value_name("BLOCK"),
+ "set initialization vector")
+ ("input,i",
+ boost::program_options::value<std::string>(&input_path)
+ ->required()
+ ->value_name("PATH"),
+ "set input file path")
+ ("output,o",
+ boost::program_options::value<std::string>(&output_path)
+ ->required()
+ ->value_name("PATH"),
+ "set output file path");
+ }
+
+ const char* get_short_description() const override
+ {
+ return "[-h|--help] [-a|--algorithm NAME] [-m|--mode MODE]"
+ " [-k|--key KEY] [-v|--iv BLOCK]"
+ " [-i|--input PATH] [-o|--output PATH]";
+ }
+
+ void parse(int argc, char** argv) override
+ {
+ SettingsParser::parse(argc, argv);
+
+ if (aes::mode_requires_init_vector(mode) && iv.empty())
+ {
+ throw boost::program_options::error{
+ "an initialization vector is required for the selected mode of operation"};
+ }
+ }
+};
diff --git a/aesxx/utils/helpers/bmp.hpp b/aesxx/utils/helpers/bmp.hpp
new file mode 100644
index 0000000..b4b283b
--- /dev/null
+++ b/aesxx/utils/helpers/bmp.hpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2016 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include <windows.h>
+
+#include <cstddef>
+#include <cstring>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace bmp
+{
+ class BmpFile
+ {
+ public:
+ BmpFile(std::vector<char>&& buffer)
+ : buffer{std::move(buffer)}
+ , header_size{extract_pixels_offset()}
+ { }
+
+ const void* get_buffer() const { return buffer.data(); }
+
+ std::size_t get_size() const { return buffer.size(); }
+
+ std::size_t get_header_size() const { return header_size; }
+
+ const void* get_pixels() const
+ {
+ return buffer.data() + get_header_size();
+ }
+
+ std::size_t get_pixels_size() const
+ {
+ return get_size() - get_header_size();
+ }
+
+ void replace_pixels(std::vector<unsigned char>&& pixels)
+ {
+ buffer.resize(get_header_size() + pixels.size());
+ std::memcpy(buffer.data() + get_header_size(), pixels.data(), pixels.size());
+ }
+
+ private:
+ std::size_t extract_pixels_offset() const
+ {
+ const auto header = reinterpret_cast<const BITMAPFILEHEADER*>(get_buffer());
+ return header->bfOffBits;
+ }
+
+ std::vector<char> buffer;
+ std::size_t header_size;
+ };
+}
diff --git a/aesxx/utils/helpers/command_line.hpp b/aesxx/utils/helpers/command_line.hpp
new file mode 100644
index 0000000..2e4d803
--- /dev/null
+++ b/aesxx/utils/helpers/command_line.hpp
@@ -0,0 +1,87 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
+
+#include <exception>
+#include <iostream>
+#include <ostream>
+#include <string>
+
+namespace command_line
+{
+ class SettingsParser
+ {
+ public:
+ explicit SettingsParser(const std::string& argv0)
+ : prog_name{extract_filename(argv0)}
+ {
+ visible.add_options()
+ ("help,h",
+ "show this message and exit");
+ }
+
+ virtual ~SettingsParser() = default;
+
+ virtual const char* get_short_description() const
+ {
+ return "[--option VALUE]...";
+ }
+
+ virtual void parse(int argc, char* argv[])
+ {
+ boost::program_options::options_description all;
+ all.add(hidden).add(visible);
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::command_line_parser{argc, argv}
+ .options(all)
+ .positional(positional)
+ .run(),
+ vm);
+ if (vm.count("help"))
+ exit_with_usage = true;
+ else
+ boost::program_options::notify(vm);
+ }
+
+ bool exit_with_usage = false;
+
+ void usage() const
+ {
+ std::cout << *this;
+ }
+
+ void usage_error(const std::exception& e) const
+ {
+ std::cerr << "usage error: " << e.what() << '\n';
+ std::cerr << *this;
+ }
+
+ protected:
+ boost::program_options::options_description hidden;
+ boost::program_options::options_description visible;
+ boost::program_options::positional_options_description positional;
+
+ private:
+ static std::string extract_filename(const std::string& path)
+ {
+ return boost::filesystem::path{path}.filename().string();
+ }
+
+ const std::string prog_name;
+
+ friend std::ostream& operator<<(std::ostream& os, const SettingsParser& parser)
+ {
+ const auto short_descr = parser.get_short_description();
+ os << "usage: " << parser.prog_name << ' ' << short_descr << '\n';
+ os << parser.visible;
+ return os;
+ }
+ };
+}
diff --git a/aesxx/utils/helpers/file.hpp b/aesxx/utils/helpers/file.hpp
new file mode 100644
index 0000000..48e4c51
--- /dev/null
+++ b/aesxx/utils/helpers/file.hpp
@@ -0,0 +1,69 @@
+// Copyright (c) 2016 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "AES tools" project.
+// For details, see https://github.com/egor-tensin/aes-tools.
+// Distributed under the MIT License.
+
+#include <cstddef>
+
+#include <fstream>
+#include <iterator>
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace file
+{
+ inline std::size_t cast_to_size_t(std::streamoff size)
+ {
+ if (size < 0)
+ throw std::range_error{"file::cast_to_size_t: something went really wrong"};
+ typedef std::make_unsigned<std::streamoff>::type unsigned_streamoff;
+ if (static_cast<unsigned_streamoff>(size) > std::numeric_limits<std::size_t>::max())
+ throw std::range_error{"file::cast_to_size_t: this file is too large"};
+ return static_cast<std::size_t>(size);
+ }
+
+ inline std::size_t get_file_size(const std::string& path)
+ {
+ std::ifstream ifs;
+ ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit);
+ ifs.open(path, std::ifstream::binary | std::ifstream::ate);
+ return cast_to_size_t(ifs.tellg());
+ }
+
+ inline std::vector<char> read_file(const std::string& path)
+ {
+ const auto size = get_file_size(path);
+
+ std::ifstream ifs;
+ ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit);
+ ifs.open(path, std::ifstream::binary);
+
+ std::vector<char> src_buf;
+ src_buf.reserve(size);
+ src_buf.assign(
+ std::istreambuf_iterator<char>{ifs},
+ std::istreambuf_iterator<char>{});
+ return src_buf;
+ }
+
+ inline void write_file(
+ const std::string& path,
+ const void* buffer,
+ const std::size_t size)
+ {
+ std::ofstream ofs;
+ ofs.exceptions(std::ofstream::badbit | std::ofstream::failbit);
+ ofs.open(path, std::ofstream::binary);
+ ofs.write(reinterpret_cast<const char*>(buffer), size);
+ }
+
+ inline void write_file(
+ const std::string& path,
+ const std::vector<unsigned char>& src)
+ {
+ write_file(path, src.data(), src.size());
+ }
+}