From 1db94ae5d2201edb5f9421c2c30be049efc678f6 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sun, 27 Dec 2015 12:56:13 +0300 Subject: utils: refactor command line parsing --- test/cavp.py | 22 +++---- test/nist-sp-800-38a.py | 14 ++--- test/toolkit.py | 78 +++++++++++++++---------- utils/block_cmd_parser.hpp | 143 ++++++++++++++++++++++++++++++++++++++++----- utils/decrypt_block.cpp | 118 +++++++++++++------------------------ utils/decrypt_bmp.cpp | 78 ++++++++++--------------- utils/decrypt_file.cpp | 62 ++++++++------------ utils/encrypt_block.cpp | 118 +++++++++++++------------------------ utils/encrypt_bmp.cpp | 78 ++++++++++--------------- utils/encrypt_file.cpp | 70 +++++++++------------- utils/file_cmd_parser.hpp | 96 +++++++++++++++--------------- 11 files changed, 437 insertions(+), 440 deletions(-) diff --git a/test/cavp.py b/test/cavp.py index 2508bda..fb719f4 100644 --- a/test/cavp.py +++ b/test/cavp.py @@ -80,24 +80,24 @@ class _TestVectorsFile: init_vectors = self._parser.get(section, 'iv') return keys, plaintexts, ciphertexts, init_vectors - def _run_tests(self, tool, inputs, expected_output): + def _run_tests(self, tool, inputs, expected_output, use_boxes=False): for expected_output_chunk, input_chunk in _split_into_chunks(expected_output, list(inputs)): - actual_output = tool(self.algorithm(), self.mode(), input_chunk) + actual_output = tool(self.algorithm(), self.mode(), input_chunk, use_boxes=use_boxes) if not _assert_output(actual_output, expected_output_chunk): return _TestExitCode.FAILURE return _TestExitCode.SUCCESS - def run_encryption_tests(self, tools): + def run_encryption_tests(self, tools, use_boxes=False): logging.info('Running encryption tests...') keys, plaintexts, ciphertexts, init_vectors = self._extract_test_data('ENCRYPT') inputs = _gen_encryption_inputs(keys, plaintexts, init_vectors) - return self._run_tests(tools.run_encrypt_block, inputs, ciphertexts) + return self._run_tests(tools.run_encrypt_block, inputs, ciphertexts, use_boxes) - def run_decryption_tests(self, tools): + def run_decryption_tests(self, tools, use_boxes=False): logging.info('Running decryption tests...') keys, plaintexts, ciphertexts, init_vectors = self._extract_test_data('DECRYPT') inputs = _gen_decryption_inputs(keys, ciphertexts, init_vectors) - return self._run_tests(tools.run_decrypt_block, inputs, plaintexts) + return self._run_tests(tools.run_decrypt_block, inputs, plaintexts, use_boxes) def _parse(self): logging.info('Trying to parse test vectors file name \'{0}\'...'.format(self._fn)) @@ -145,7 +145,7 @@ class _TestVectorsFile: logging.warn('Unknown or unsupported mode: ' + self._fn) return None -def _parse_archive_and_run_tests(tools, archive_path): +def _parse_archive_and_run_tests(tools, archive_path, use_boxes=False): archive = zipfile.ZipFile(archive_path) exit_codes = [] for fn in archive.namelist(): @@ -153,13 +153,13 @@ def _parse_archive_and_run_tests(tools, archive_path): if member.recognized(): member.parse() try: - exit_codes.append(member.run_encryption_tests(tools)) + exit_codes.append(member.run_encryption_tests(tools, use_boxes)) except Exception as e: logging.error('Encountered an exception!') logging.exception(e) exit_codes.append(_TestExitCode.ERROR) try: - exit_codes.append(member.run_decryption_tests(tools)) + exit_codes.append(member.run_decryption_tests(tools, use_boxes)) except Exception as e: logging.error('Encountered an exception!') logging.exception(e) @@ -201,5 +201,5 @@ if __name__ == '__main__': logging_options['filename'] = args.log logging.basicConfig(**logging_options) - tools = toolkit.Tools(args.path, use_sde=args.sde, use_boxes=args.box) - _parse_archive_and_run_tests(tools, args.archive) + tools = toolkit.Tools(args.path, use_sde=args.sde) + _parse_archive_and_run_tests(tools, args.archive, use_boxes=args.box) diff --git a/test/nist-sp-800-38a.py b/test/nist-sp-800-38a.py index 7189dde..05f0a39 100644 --- a/test/nist-sp-800-38a.py +++ b/test/nist-sp-800-38a.py @@ -146,7 +146,7 @@ def _assert_output(actual, expected): class _TestExitCode: SUCCESS, FAILURE, ERROR, SKIPPED = range(4) -def _run_encryption_tests(tools, algo, mode): +def _run_encryption_tests(tools, algo, mode, use_boxes=False): logging.info('Running encryption tests...') key = _keys[algo] iv = None @@ -154,13 +154,13 @@ def _run_encryption_tests(tools, algo, mode): iv = _init_vectors[algo][mode] ciphertexts = _ciphertexts[algo][mode] _input = toolkit.EncryptionInput(key, _plaintexts, iv=iv) - actual_output = tools.run_encrypt_block(algo, mode, _input) + actual_output = tools.run_encrypt_block(algo, mode, _input, use_boxes) if _assert_output(actual_output, ciphertexts): return _TestExitCode.SUCCESS else: return _TestExitCode.FAILURE -def _run_decryption_tests(tools, algo, mode): +def _run_decryption_tests(tools, algo, mode, use_boxes=False): logging.info('Running decryption tests...') key = _keys[algo] iv = None @@ -168,7 +168,7 @@ def _run_decryption_tests(tools, algo, mode): iv = _init_vectors[algo][mode] ciphertexts = _ciphertexts[algo][mode] _input = toolkit.DecryptionInput(key, ciphertexts, iv=iv) - actual_output = tools.run_decrypt_block(algo, mode, _input) + actual_output = tools.run_decrypt_block(algo, mode, _input, use_boxes) if _assert_output(actual_output, _plaintexts): return _TestExitCode.SUCCESS else: @@ -186,7 +186,7 @@ if __name__ == '__main__': parser.add_argument('--log', '-l', help='set log file path') args = parser.parse_args() - tools = toolkit.Tools(args.path, use_sde=args.sde, use_boxes=args.box) + tools = toolkit.Tools(args.path, use_sde=args.sde) logging_options = { 'format': '%(asctime)s | %(module)s | %(levelname)s | %(message)s', @@ -216,13 +216,13 @@ if __name__ == '__main__': mode = maybe_mode logging.info('Mode: ' + mode) try: - exit_codes.append(_run_encryption_tests(tools, algo, mode)) + exit_codes.append(_run_encryption_tests(tools, algo, mode, use_boxes=args.box)) except Exception as e: logging.error('Encountered an exception!') logging.exception(e) exit_codes.append(_TestExitCode.ERROR) try: - exit_codes.append(_run_decryption_tests(tools, algo, mode)) + exit_codes.append(_run_decryption_tests(tools, algo, mode, use_boxes=args.box)) except Exception as e: logging.error('Encountered an exception!') logging.exception(e) diff --git a/test/toolkit.py b/test/toolkit.py index 50a42c9..170bccf 100644 --- a/test/toolkit.py +++ b/test/toolkit.py @@ -25,10 +25,10 @@ def mode_requires_init_vector(mode): return mode != ECB def to_supported_algorithm(s): - algo = is_algorithm_supported(s) - if algo is None: + algorithm = is_algorithm_supported(s) + if algorithm is None: raise NotImplementedError('unsupported algorithm ' + s) - return algo + return algorithm def is_algorithm_supported(s): s = s.lower() @@ -77,7 +77,7 @@ class DecryptionInput: return args class Tools: - def __init__(self, search_dirs, use_sde=False, use_boxes=False): + def __init__(self, search_dirs, use_sde=False): if search_dirs: if isinstance(search_dirs, str): os.environ['PATH'] += os.pathsep + search_dirs @@ -86,7 +86,6 @@ class Tools: else: os.environ['PATH'] += os.pathsep + str(search_dirs) self._use_sde = use_sde - self._use_boxes = use_boxes self._logger = logging.getLogger(__name__) _ENCRYPT_BLOCK = 'encrypt_block.exe' @@ -94,11 +93,8 @@ class Tools: _ENCRYPT_FILE = 'encrypt_file.exe' _DECRYPT_FILE = 'decrypt_file.exe' - def run(self, tool_path, algo, mode, args): + def run(self, tool_path, args): cmd_list = ['sde', '--', tool_path] if self._use_sde else [tool_path] - if self._use_boxes: - cmd_list.append('-b') - cmd_list.extend(('-a', algo, '-m', mode)) cmd_list.extend(args) logging.info('Trying to execute: {0}'.format( subprocess.list2cmdline(cmd_list))) @@ -126,32 +122,54 @@ class Tools: args.extend(tail.to_args()) return args - def run_encrypt_block(self, algo, mode, inputs): + def run_encrypt_block(self, algorithm, mode, inputs, use_boxes=False): + args = [ + '--algorithm', algorithm, + '--mode', mode, + ] + if use_boxes: + args.append('--box') if isinstance(inputs, collections.Iterable): - args = self._block_inputs_to_args(iter(inputs)) + args.extend(self._block_inputs_to_args(iter(inputs))) else: - args = inputs.to_args() - return self.run(self._ENCRYPT_BLOCK, algo, mode, args) - - def run_decrypt_block(self, algo, mode, inputs): + args.extend(inputs.to_args()) + return self.run(self._ENCRYPT_BLOCK, args) + + def run_decrypt_block(self, algorithm, mode, inputs, use_boxes=False): + args = [ + '--algorithm', algorithm, + '--mode', mode, + ] + if use_boxes: + args.append('--box') if isinstance(inputs, collections.Iterable): - args = self._block_inputs_to_args(iter(inputs)) + args.extend(self._block_inputs_to_args(iter(inputs))) else: - args = inputs.to_args() - return self.run(self._DECRYPT_BLOCK, algo, mode, args) - - def run_encrypt_file(self, algo, mode, key, input_path, output_path, iv=None): + args.extend(inputs.to_args()) + return self.run(self._DECRYPT_BLOCK, args) + + def run_encrypt_file(self, algorithm, mode, key, input_path, output_path, iv=None): + args = [ + '--algorithm', algorithm, + '--mode', mode, + '--key', key, + '--input-path', input_path, + '--output-path', output_path] if mode_requires_init_vector(mode): if not iv: - raise ValueError('mode \'{}\' requires init vector'.format(mode)) - return self.run(self._ENCRYPT_FILE, algo, mode, (key, iv, input_path, output_path)) - else: - return self.run(self._ENCRYPT_FILE, algo, mode, (key, input_path, output_path)) - - def run_decrypt_file(self, algo, mode, key, input_path, output_path, iv=None): + raise ValueError('mode \'{}\' requires initialization vector'.format(mode)) + args.extend(('--iv', iv)) + return self.run(self._ENCRYPT_FILE, args) + + def run_decrypt_file(self, algorithm, mode, key, input_path, output_path, iv=None): + args = [ + '--algorithm', algorithm, + '--mode', mode, + '--key', key, + '--input-path', input_path, + '--output-path', output_path] if mode_requires_init_vector(mode): if not iv: - raise ValueError('mode \'{}\' requires init vector'.format(mode)) - return self.run(self._DECRYPT_FILE, algo, mode, (key, iv, input_path, output_path)) - else: - return self.run(self._DECRYPT_FILE, algo, mode, (key, input_path, output_path)) + raise ValueError('mode \'{}\' requires initialization vector'.format(mode)) + args.extend(('--iv', iv)) + return self.run(self._DECRYPT_FILE, args) diff --git a/utils/block_cmd_parser.hpp b/utils/block_cmd_parser.hpp index 3468d58..988ef52 100644 --- a/utils/block_cmd_parser.hpp +++ b/utils/block_cmd_parser.hpp @@ -16,8 +16,11 @@ #include #include +#include +#include #include #include +#include #include namespace @@ -40,26 +43,87 @@ namespace "the selected mode of operation is not implemented"); } + class CommandLineParser; + + class Input + { + public: + Input( + std::string&& key_string, + std::string&& iv_string, + std::vector&& input_block_strings) + : key_string(std::move(key_string)) + , iv_string(std::make_pair(true, std::move(iv_string))) + , input_block_strings(input_block_strings) + { } + + Input( + std::string&& key_string, + std::vector&& input_block_strings) + : key_string(std::move(key_string)) + , iv_string(std::make_pair(false, std::string())) + , input_block_strings(std::move(input_block_strings)) + { } + + const std::string& get_key_string() const { return key_string; } + + const std::string& get_iv_string() const + { + if (!iv_string.first) + throw_iv_required(); + return iv_string.second; + } + + const std::vector& get_input_block_strings() const + { + return input_block_strings; + } + + private: + const std::string key_string; + const std::pair iv_string; + const std::vector input_block_strings; + }; + + class Settings + { + public: + aesni::Algorithm get_algorithm() const { return algorithm; } + aesni::Mode get_mode() const { return mode; } + + bool use_boxes() const { return use_boxes_flag; } + bool verbose() const { return verbose_flag; } + + private: + aesni::Algorithm algorithm; + aesni::Mode mode; + + bool use_boxes_flag = false; + bool verbose_flag = false; + + friend class CommandLineParser; + }; + class CommandLineParser { public: CommandLineParser(const std::string& argv0) : prog_name(boost::filesystem::path(argv0).filename().string()) , options("Options") + { } + + void parse(Settings& settings, int argc, char** argv, std::vector& inputs) { namespace po = boost::program_options; options.add_options() ("help,h", "show this message and exit") - ("box,b", po::bool_switch(&use_boxes)->default_value(false), "use the \"boxes\" interface") - ("mode,m", po::value(&mode)->required(), "set mode of operation") - ("algorithm,a", po::value(&algorithm)->required(), "set algorithm") - ("verbose,v", po::bool_switch(&verbose)->default_value(false), "enable verbose output"); - } + ("box,b", po::bool_switch(&settings.use_boxes_flag)->default_value(false), "use the \"boxes\" interface") + ("mode,m", po::value(&settings.mode)->required(), "set mode of operation") + ("algorithm,a", po::value(&settings.algorithm)->required(), "set algorithm") + ("verbose,v", po::bool_switch(&settings.verbose_flag)->default_value(false), "enable verbose output"); - void parse(int argc, char** argv) - { - namespace po = boost::program_options; + std::vector args; po::options_description hidden_options; hidden_options.add_options() @@ -84,17 +148,66 @@ namespace } po::notify(vm); + + parse_inputs(settings, inputs, std::deque( + std::make_move_iterator(args.begin()), + std::make_move_iterator(args.end()) + )); } - bool requested_help() const { return help_flag; } - - aesni::Mode mode; - aesni::Algorithm algorithm; - bool use_boxes; - std::vector args; - bool verbose; + bool exit_with_usage() const { return help_flag; } private: + static void parse_inputs( + const Settings& settings, + std::vector& inputs, + std::deque&& args) + { + while (!args.empty()) + { + auto key_string = std::move(args.front()); + args.pop_front(); + + std::string iv_string; + + if (aesni::mode_requires_initialization_vector(settings.get_mode())) + { + if (args.empty()) + throw_iv_required(); + iv_string = std::move(args.front()); + args.pop_front(); + } + + std::vector input_block_strings; + + while (!args.empty()) + { + if (args.front() == "--") + { + args.pop_front(); + break; + } + + input_block_strings.emplace_back(std::move(args.front())); + args.pop_front(); + } + + if (aesni::mode_requires_initialization_vector(settings.get_mode())) + { + inputs.emplace_back( + std::move(key_string), + std::move(iv_string), + std::move(input_block_strings)); + } + else + { + inputs.emplace_back( + std::move(key_string), + std::move(input_block_strings)); + } + } + } + const std::string prog_name; boost::program_options::options_description options; diff --git a/utils/decrypt_block.cpp b/utils/decrypt_block.cpp index 30409e0..a8c9625 100644 --- a/utils/decrypt_block.cpp +++ b/utils/decrypt_block.cpp @@ -13,7 +13,6 @@ #include -#include #include #include #include @@ -23,40 +22,31 @@ namespace { template void decrypt_with_mode( - const std::string& key_str, - std::deque& ciphertexts, + const Input& input, bool verbose = false) { typename aesni::Types::Block iv; if (aesni::ModeRequiresInitializationVector()) { - if (ciphertexts.empty()) - throw_iv_required(); - - aesni::from_string(iv, ciphertexts.front()); - ciphertexts.pop_front(); - + aesni::from_string(iv, input.get_iv_string()); if (verbose) dump_iv(iv); } typename aesni::Types::Key key; - aesni::from_string(key, key_str); - + aesni::from_string(key, input.get_key_string()); if (verbose) dump_key(key); aesni::DecryptWrapper decrypt(key, iv); - if (verbose) dump_wrapper(decrypt); - while (!ciphertexts.empty()) + for (const auto& input_block_string : input.get_input_block_strings()) { typename aesni::Types::Block ciphertext, plaintext; - aesni::from_string(ciphertext, ciphertexts.front()); - ciphertexts.pop_front(); + aesni::from_string(ciphertext, input_block_string); decrypt.decrypt_block(ciphertext, plaintext); @@ -68,7 +58,7 @@ namespace } else { - std::cout << aesni::to_string(plaintext) << "\n"; + std::cout << aesni::to_string(plaintext) << '\n'; } } } @@ -76,30 +66,29 @@ namespace template void decrypt_with_algorithm( aesni::Mode mode, - const std::string& key_str, - std::deque& ciphertexts, + const Input& input, bool verbose = false) { switch (mode) { case AESNI_ECB: - decrypt_with_mode(key_str, ciphertexts, verbose); + decrypt_with_mode(input, verbose); break; case AESNI_CBC: - decrypt_with_mode(key_str, ciphertexts, verbose); + decrypt_with_mode(input, verbose); break; case AESNI_CFB: - decrypt_with_mode(key_str, ciphertexts, verbose); + decrypt_with_mode(input, verbose); break; case AESNI_OFB: - decrypt_with_mode(key_str, ciphertexts, verbose); + decrypt_with_mode(input, verbose); break; case AESNI_CTR: - decrypt_with_mode(key_str, ciphertexts, verbose); + decrypt_with_mode(input, verbose); break; default: @@ -111,22 +100,21 @@ namespace void decrypt_using_cxx_api( aesni::Algorithm algorithm, aesni::Mode mode, - const std::string& key_str, - std::deque& ciphertexts, + const Input& input, bool verbose = false) { switch (algorithm) { case AESNI_AES128: - decrypt_with_algorithm(mode, key_str, ciphertexts, verbose); + decrypt_with_algorithm(mode, input, verbose); break; case AESNI_AES192: - decrypt_with_algorithm(mode, key_str, ciphertexts, verbose); + decrypt_with_algorithm(mode, input, verbose); break; case AESNI_AES256: - decrypt_with_algorithm(mode, key_str, ciphertexts, verbose); + decrypt_with_algorithm(mode, input, verbose); break; default: @@ -137,46 +125,41 @@ namespace void decrypt_using_particular_box( aesni::Box& box, - std::deque& ciphertexts) + const std::vector& input_block_strings) { - while (!ciphertexts.empty()) + for (const auto& input_block_string : input_block_strings) { aesni::Box::Block ciphertext; - box.parse_block(ciphertext, ciphertexts.front()); - ciphertexts.pop_front(); + box.parse_block(ciphertext, input_block_string); aesni::Box::Block plaintext; box.decrypt_block(ciphertext, plaintext); - - std::cout << box.format_block(plaintext) << "\n"; + std::cout << box.format_block(plaintext) << '\n'; } } void decrypt_using_boxes( aesni::Algorithm algorithm, aesni::Mode mode, - const std::string& key_str, - std::deque& ciphertexts) + const Input& input) { aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, key_str); + aesni::Box::parse_key(key, algorithm, input.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (ciphertexts.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, ciphertexts.front()); - ciphertexts.pop_front(); + aesni::Box::parse_block(iv, algorithm, input.get_iv_string()); decrypt_using_particular_box( - aesni::Box(algorithm, key, mode, iv), ciphertexts); + aesni::Box(algorithm, key, mode, iv), + input.get_input_block_strings()); } else { decrypt_using_particular_box( - aesni::Box(algorithm, key), ciphertexts); + aesni::Box(algorithm, key), + input.get_input_block_strings()); } } } @@ -188,53 +171,32 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + Settings settings; + std::vector inputs; + cmd_parser.parse(settings, argc, argv, inputs); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - while (!args.empty()) + for (const auto& input : inputs) { - const auto key = args.front(); - args.pop_front(); - - std::deque ciphertexts; - - while (!args.empty()) - { - if (args.front() == "--") - { - args.pop_front(); - break; - } - - ciphertexts.push_back(args.front()); - args.pop_front(); - } - - if (cmd_parser.use_boxes) + if (settings.use_boxes()) { decrypt_using_boxes( - cmd_parser.algorithm, - cmd_parser.mode, - key, - ciphertexts); + settings.get_algorithm(), + settings.get_mode(), + input); } else { decrypt_using_cxx_api( - cmd_parser.algorithm, - cmd_parser.mode, - key, - ciphertexts, - cmd_parser.verbose); + settings.get_algorithm(), + settings.get_mode(), + input, + settings.verbose()); } } diff --git a/utils/decrypt_bmp.cpp b/utils/decrypt_bmp.cpp index a326828..e63155d 100644 --- a/utils/decrypt_bmp.cpp +++ b/utils/decrypt_bmp.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -43,12 +42,12 @@ namespace ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit); ifs.open(path, std::ifstream::binary); - std::vector src_buf; - src_buf.reserve(size); - src_buf.assign( + std::vector ciphertext_buf; + ciphertext_buf.reserve(size); + ciphertext_buf.assign( std::istreambuf_iterator(ifs), std::istreambuf_iterator()); - return src_buf; + return ciphertext_buf; } void write_file( @@ -63,64 +62,54 @@ namespace void decrypt_bmp( aesni::Box& box, - std::deque& args) + const std::string& ciphertext_path, + const std::string& plaintext_path) { - if (args.empty()) - throw_src_path_required(); - const auto src_path = args.front(); - args.pop_front(); + const auto ciphertext_buf = read_file(ciphertext_path); - if (args.empty()) - throw_dest_path_required(); - const auto dest_path = args.front(); - args.pop_front(); - - const auto src_buf = read_file(src_path); - - const auto bmp_header = reinterpret_cast(src_buf.data()); + const auto bmp_header = reinterpret_cast(ciphertext_buf.data()); const auto header_size = bmp_header->bfOffBits; - const auto cipherpixels = src_buf.data() + header_size; - const auto cipherpixels_size = src_buf.size() - header_size; + const auto cipherpixels = ciphertext_buf.data() + header_size; + const auto cipherpixels_size = ciphertext_buf.size() - header_size; const auto pixels = box.decrypt_buffer( cipherpixels, cipherpixels_size); - std::vector dest_buf(header_size + pixels.size()); - std::memcpy(&dest_buf[0], bmp_header, header_size); - std::memcpy(&dest_buf[0] + header_size, pixels.data(), pixels.size()); + std::vector plaintext_buf(header_size + pixels.size()); + std::memcpy(plaintext_buf.data(), bmp_header, header_size); + std::memcpy(plaintext_buf.data() + header_size, pixels.data(), pixels.size()); - write_file(dest_path, dest_buf); + write_file(plaintext_path, plaintext_buf); } - void decrypt_bmp( - aesni::Algorithm algorithm, - aesni::Mode mode, - std::deque& args) + void decrypt_bmp(const Settings& settings) { - if (args.empty()) - throw_key_required(); + const auto algorithm = settings.get_algorithm(); + const auto mode = settings.get_mode(); + + const auto ciphertext_path = settings.get_input_path(); + const auto plaintext_path = settings.get_output_path(); aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_key(key, algorithm, settings.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (args.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_block(iv, algorithm, settings.get_iv_string()); decrypt_bmp( - aesni::Box(algorithm, key, mode, iv), args); + aesni::Box(algorithm, key, mode, iv), + ciphertext_path, + plaintext_path); } else { decrypt_bmp( - aesni::Box(algorithm, key), args); + aesni::Box(algorithm, key), + ciphertext_path, + plaintext_path); } } } @@ -132,19 +121,16 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + Settings settings; + cmd_parser.parse(settings, argc, argv); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - decrypt_bmp(cmd_parser.algorithm, cmd_parser.mode, args); + decrypt_bmp(settings); } catch (const boost::program_options::error& e) { diff --git a/utils/decrypt_file.cpp b/utils/decrypt_file.cpp index 96aec62..2264926 100644 --- a/utils/decrypt_file.cpp +++ b/utils/decrypt_file.cpp @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -60,52 +59,42 @@ namespace void decrypt_file( aesni::Box& box, - std::deque& args) + const std::string& ciphertext_path, + const std::string& plaintext_path) { - if (args.empty()) - throw_src_path_required(); - const auto src_path = args.front(); - args.pop_front(); - - if (args.empty()) - throw_dest_path_required(); - const auto dest_path = args.front(); - args.pop_front(); - - const auto src_buf = read_file(src_path); - const auto dest_buf = box.decrypt_buffer( - src_buf.data(), src_buf.size()); - write_file(dest_path, dest_buf); + const auto ciphertext_buf = read_file(ciphertext_path); + const auto plaintext_buf = box.decrypt_buffer( + ciphertext_buf.data(), ciphertext_buf.size()); + write_file(plaintext_path, plaintext_buf); } - void decrypt_file( - aesni::Algorithm algorithm, - aesni::Mode mode, - std::deque& args) + void decrypt_file(const Settings& settings) { - if (args.empty()) - throw_key_required(); + const auto algorithm = settings.get_algorithm(); + const auto mode = settings.get_mode(); + + const auto ciphertext_path = settings.get_input_path(); + const auto plaintext_path = settings.get_output_path(); aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_key(key, algorithm, settings.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (args.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_block(iv, algorithm, settings.get_iv_string()); decrypt_file( - aesni::Box(algorithm, key, mode, iv), args); + aesni::Box(algorithm, key, mode, iv), + ciphertext_path, + plaintext_path); } else { decrypt_file( - aesni::Box(algorithm, key), args); + aesni::Box(algorithm, key), + ciphertext_path, + plaintext_path); } } } @@ -117,19 +106,16 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + Settings settings; + cmd_parser.parse(settings, argc, argv); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - decrypt_file(cmd_parser.algorithm, cmd_parser.mode, args); + decrypt_file(settings); } catch (const boost::program_options::error& e) { diff --git a/utils/encrypt_block.cpp b/utils/encrypt_block.cpp index 022c237..724e8c1 100644 --- a/utils/encrypt_block.cpp +++ b/utils/encrypt_block.cpp @@ -13,7 +13,6 @@ #include -#include #include #include #include @@ -23,40 +22,32 @@ namespace { template void encrypt_with_mode( - const std::string& key_str, - std::deque& plaintexts, + const Input& input, bool verbose = false) { typename aesni::Types::Block iv; if (aesni::ModeRequiresInitializationVector::value) { - if (plaintexts.empty()) - throw_iv_required(); - - aesni::from_string(iv, plaintexts.front()); - plaintexts.pop_front(); - + aesni::from_string(iv, input.get_iv_string()); if (verbose) dump_iv(iv); } typename aesni::Types::Key key; - aesni::from_string(key, key_str); - + aesni::from_string(key, input.get_key_string()); if (verbose) dump_key(key); aesni::EncryptWrapper encrypt(key, iv); - if (verbose) dump_wrapper(encrypt); - while (!plaintexts.empty()) + for (const auto& input_block_string : input.get_input_block_strings()) { typename aesni::Types::Block plaintext, ciphertext; - aesni::from_string(plaintext, plaintexts.front()); - plaintexts.pop_front(); + aesni::from_string(plaintext, input_block_string); + encrypt.encrypt_block(plaintext, ciphertext); if (verbose) @@ -67,7 +58,7 @@ namespace } else { - std::cout << aesni::to_string(ciphertext) << "\n"; + std::cout << aesni::to_string(ciphertext) << '\n'; } } } @@ -75,30 +66,29 @@ namespace template void encrypt_with_algorithm( aesni::Mode mode, - const std::string& key_str, - std::deque& plaintexts, + const Input& input, bool verbose = false) { switch (mode) { case AESNI_ECB: - encrypt_with_mode(key_str, plaintexts, verbose); + encrypt_with_mode(input, verbose); break; case AESNI_CBC: - encrypt_with_mode(key_str, plaintexts, verbose); + encrypt_with_mode(input, verbose); break; case AESNI_CFB: - encrypt_with_mode(key_str, plaintexts, verbose); + encrypt_with_mode(input, verbose); break; case AESNI_OFB: - encrypt_with_mode(key_str, plaintexts, verbose); + encrypt_with_mode(input, verbose); break; case AESNI_CTR: - encrypt_with_mode(key_str, plaintexts, verbose); + encrypt_with_mode(input, verbose); break; default: @@ -110,22 +100,21 @@ namespace void encrypt_using_cxx_api( aesni::Algorithm algorithm, aesni::Mode mode, - const std::string& key_str, - std::deque& plaintexts, + const Input& input, bool verbose = false) { switch (algorithm) { case AESNI_AES128: - encrypt_with_algorithm(mode, key_str, plaintexts, verbose); + encrypt_with_algorithm(mode, input, verbose); break; case AESNI_AES192: - encrypt_with_algorithm(mode, key_str, plaintexts, verbose); + encrypt_with_algorithm(mode, input, verbose); break; case AESNI_AES256: - encrypt_with_algorithm(mode, key_str, plaintexts, verbose); + encrypt_with_algorithm(mode, input, verbose); break; default: @@ -136,47 +125,39 @@ namespace void encrypt_using_particular_box( aesni::Box& box, - std::deque& plaintexts) + const std::vector& input_block_strings) { - while (!plaintexts.empty()) + for (const auto& input_block_string : input_block_strings) { aesni::Box::Block plaintext; - box.parse_block( - plaintext, plaintexts.front()); - plaintexts.pop_front(); + box.parse_block(plaintext, input_block_string); aesni::Box::Block ciphertext; box.encrypt_block(plaintext, ciphertext); - - std::cout << box.format_block(ciphertext) << "\n"; + std::cout << box.format_block(ciphertext) << '\n'; } } void encrypt_using_boxes( aesni::Algorithm algorithm, aesni::Mode mode, - const std::string& key_str, - std::deque& plaintexts) + const Input& input) { aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, key_str); + aesni::Box::parse_key(key, algorithm, input.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (plaintexts.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, plaintexts.front()); - plaintexts.pop_front(); + aesni::Box::parse_block(iv, algorithm, input.get_iv_string()); encrypt_using_particular_box( - aesni::Box(algorithm, key, mode, iv), plaintexts); + aesni::Box(algorithm, key, mode, iv), input.get_input_block_strings()); } else { encrypt_using_particular_box( - aesni::Box(algorithm, key), plaintexts); + aesni::Box(algorithm, key), input.get_input_block_strings()); } } } @@ -188,53 +169,32 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + std::vector inputs; + Settings settings; + cmd_parser.parse(settings, argc, argv, inputs); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - while (!args.empty()) + for (const auto& input : inputs) { - const auto key = args.front(); - args.pop_front(); - - std::deque plaintexts; - - while (!args.empty()) - { - if (args.front() == "--") - { - args.pop_front(); - break; - } - - plaintexts.push_back(args.front()); - args.pop_front(); - } - - if (cmd_parser.use_boxes) + if (settings.use_boxes()) { encrypt_using_boxes( - cmd_parser.algorithm, - cmd_parser.mode, - key, - plaintexts); + settings.get_algorithm(), + settings.get_mode(), + input); } else { encrypt_using_cxx_api( - cmd_parser.algorithm, - cmd_parser.mode, - key, - plaintexts, - cmd_parser.verbose); + settings.get_algorithm(), + settings.get_mode(), + input, + settings.verbose()); } } diff --git a/utils/encrypt_bmp.cpp b/utils/encrypt_bmp.cpp index 2f019d8..3ac5906 100644 --- a/utils/encrypt_bmp.cpp +++ b/utils/encrypt_bmp.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -43,12 +42,12 @@ namespace ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit); ifs.open(path, std::ifstream::binary); - std::vector src_buf; - src_buf.reserve(size); - src_buf.assign( + std::vector plaintext_buf; + plaintext_buf.reserve(size); + plaintext_buf.assign( std::istreambuf_iterator(ifs), std::istreambuf_iterator()); - return src_buf; + return plaintext_buf; } void write_file( @@ -63,64 +62,54 @@ namespace void encrypt_bmp( aesni::Box& box, - std::deque& args) + const std::string& plaintext_path, + const std::string& ciphertext_path) { - if (args.empty()) - throw_src_path_required(); - const auto src_path = args.front(); - args.pop_front(); + const auto plaintext_buf = read_file(plaintext_path); - if (args.empty()) - throw_dest_path_required(); - const auto dest_path = args.front(); - args.pop_front(); - - const auto src_buf = read_file(src_path); - - const auto bmp_header = reinterpret_cast(src_buf.data()); + const auto bmp_header = reinterpret_cast(plaintext_buf.data()); const auto header_size = bmp_header->bfOffBits; - const auto pixels = src_buf.data() + header_size; - const auto pixels_size = src_buf.size() - header_size; + const auto pixels = plaintext_buf.data() + header_size; + const auto pixels_size = plaintext_buf.size() - header_size; const auto cipherpixels = box.encrypt_buffer( pixels, pixels_size); - std::vector dest_buf(header_size + cipherpixels.size()); - std::memcpy(&dest_buf[0], bmp_header, header_size); - std::memcpy(&dest_buf[0] + header_size, cipherpixels.data(), cipherpixels.size()); + std::vector ciphertext_buf(header_size + cipherpixels.size()); + std::memcpy(ciphertext_buf.data(), bmp_header, header_size); + std::memcpy(ciphertext_buf.data() + header_size, cipherpixels.data(), cipherpixels.size()); - write_file(dest_path, dest_buf); + write_file(ciphertext_path, ciphertext_buf); } - void encrypt_bmp( - aesni::Algorithm algorithm, - aesni::Mode mode, - std::deque& args) + void encrypt_bmp(const Settings& settings) { - if (args.empty()) - throw_key_required(); + const auto algorithm = settings.get_algorithm(); + const auto mode = settings.get_mode(); + + const auto plaintext_path = settings.get_input_path(); + const auto ciphertext_path = settings.get_output_path(); aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_key(key, algorithm, settings.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (args.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_block(iv, algorithm, settings.get_iv_string()); encrypt_bmp( - aesni::Box(algorithm, key, mode, iv), args); + aesni::Box(algorithm, key, mode, iv), + plaintext_path, + ciphertext_path); } else { encrypt_bmp( - aesni::Box(algorithm, key), args); + aesni::Box(algorithm, key), + plaintext_path, + ciphertext_path); } } } @@ -132,19 +121,16 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + Settings settings; + cmd_parser.parse(settings, argc, argv); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - encrypt_bmp(cmd_parser.algorithm, cmd_parser.mode, args); + encrypt_bmp(settings); } catch (const boost::program_options::error& e) { diff --git a/utils/encrypt_file.cpp b/utils/encrypt_file.cpp index d1dd5e8..4651928 100644 --- a/utils/encrypt_file.cpp +++ b/utils/encrypt_file.cpp @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -40,12 +39,12 @@ namespace ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit); ifs.open(path, std::ifstream::binary); - std::vector src_buf; - src_buf.reserve(size); - src_buf.assign( + std::vector plaintext_buf; + plaintext_buf.reserve(size); + plaintext_buf.assign( std::istreambuf_iterator(ifs), std::istreambuf_iterator()); - return src_buf; + return plaintext_buf; } void write_file( @@ -60,52 +59,42 @@ namespace void encrypt_file( aesni::Box& box, - std::deque& args) + const std::string& plaintext_path, + const std::string& ciphertext_path) { - if (args.empty()) - throw_src_path_required(); - const auto src_path = args.front(); - args.pop_front(); - - if (args.empty()) - throw_dest_path_required(); - const auto dest_path = args.front(); - args.pop_front(); - - const auto src_buf = read_file(src_path); - const auto dest_buf = box.encrypt_buffer( - src_buf.data(), src_buf.size()); - write_file(dest_path, dest_buf); + const auto plaintext_buf = read_file(plaintext_path); + const auto ciphertext_buf = box.encrypt_buffer( + plaintext_buf.data(), plaintext_buf.size()); + write_file(ciphertext_path, ciphertext_buf); } - void encrypt_file( - aesni::Algorithm algorithm, - aesni::Mode mode, - std::deque& args) + void encrypt_file(const Settings& settings) { - if (args.empty()) - throw_key_required(); + const auto algorithm = settings.get_algorithm(); + const auto mode = settings.get_mode(); + + const auto plaintext_path = settings.get_input_path(); + const auto ciphertext_path = settings.get_output_path(); aesni::Box::Key key; - aesni::Box::parse_key(key, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_key(key, algorithm, settings.get_key_string()); if (aesni::mode_requires_initialization_vector(mode)) { - if (args.empty()) - throw_iv_required(); - aesni::Box::Block iv; - aesni::Box::parse_block(iv, algorithm, args.front()); - args.pop_front(); + aesni::Box::parse_block(iv, algorithm, settings.get_iv_string()); encrypt_file( - aesni::Box(algorithm, key, mode, iv), args); + aesni::Box(algorithm, key, mode, iv), + plaintext_path, + ciphertext_path); } else { encrypt_file( - aesni::Box(algorithm, key), args); + aesni::Box(algorithm, key), + plaintext_path, + ciphertext_path); } } } @@ -117,19 +106,16 @@ int main(int argc, char** argv) CommandLineParser cmd_parser(argv[0]); try { - cmd_parser.parse(argc, argv); + Settings settings; + cmd_parser.parse(settings, argc, argv); - if (cmd_parser.requested_help()) + if (cmd_parser.exit_with_usage()) { std::cout << cmd_parser; return 0; } - std::deque args( - std::make_move_iterator(cmd_parser.args.begin()), - std::make_move_iterator(cmd_parser.args.end())); - - encrypt_file(cmd_parser.algorithm, cmd_parser.mode, args); + encrypt_file(settings); } catch (const boost::program_options::error& e) { diff --git a/utils/file_cmd_parser.hpp b/utils/file_cmd_parser.hpp index cf5d188..7d1470d 100644 --- a/utils/file_cmd_parser.hpp +++ b/utils/file_cmd_parser.hpp @@ -12,39 +12,51 @@ #include -#include #include #include #include #include -#include +#include namespace { - BOOST_NORETURN inline void throw_key_required() - { - throw boost::program_options::error( - "a key is required but not specified"); - } + class CommandLineParser; - BOOST_NORETURN inline void throw_iv_required() + class Settings { - throw boost::program_options::error( - "initialization vector is required for the selected mode of operation"); - } + public: + Settings() + : iv(false, std::string()) + { } - BOOST_NORETURN inline void throw_src_path_required() - { - throw boost::program_options::error( - "please, specify source file path"); - } + aesni::Mode get_mode() const { return mode; } + aesni::Algorithm get_algorithm() const { return algorithm; } - BOOST_NORETURN inline void throw_dest_path_required() - { - throw boost::program_options::error( - "please, specify destination file path"); - } + std::string get_input_path() const { return input_path; } + std::string get_output_path() const { return output_path; } + + std::string get_key_string() const { return key; } + + std::string get_iv_string() const + { + if (!iv.first) + throw boost::program_options::error("initialization vector is required for the selected mode of operation"); + return iv.second; + } + + private: + aesni::Mode mode; + aesni::Algorithm algorithm; + + std::string input_path; + std::string output_path; + std::string key; + + std::pair iv; + + friend class CommandLineParser; + }; class CommandLineParser { @@ -52,34 +64,23 @@ namespace CommandLineParser(const std::string& argv0) : prog_name(boost::filesystem::path(argv0).filename().string()) , options("Options") + { } + + void parse(Settings& settings, int argc, char** argv) { namespace po = boost::program_options; options.add_options() ("help,h", "show this message and exit") - ("mode,m", po::value(&mode)->required(), "set mode of operation") - ("algorithm,a", po::value(&algorithm)->required(), "set algorithm"); - } - - void parse(int argc, char** argv) - { - namespace po = boost::program_options; - - po::options_description hidden_options; - hidden_options.add_options() - ("positional", po::value>(&args)); - - po::options_description all_options; - all_options.add(options).add(hidden_options); - - po::positional_options_description positional_options; - positional_options.add("positional", -1); + ("mode,m", po::value(&settings.mode)->required(), "set mode of operation") + ("algorithm,a", po::value(&settings.algorithm)->required(), "set algorithm") + ("input-path,i", po::value(&settings.input_path)->required(), "set input file") + ("output-path,o", po::value(&settings.output_path)->required(), "set output file") + ("key,k", po::value(&settings.key)->required(), "set encryption key") + ("iv,v", po::value(&settings.iv.second), "set initialization vector"); po::variables_map vm; - po::store(po::command_line_parser(argc, argv) - .options(all_options) - .positional(positional_options) - .run(), vm); + po::store(po::parse_command_line(argc, argv, options), vm); if (vm.count("help")) { @@ -87,14 +88,13 @@ namespace return; } + if (vm.count("iv")) + settings.iv.first = true; + po::notify(vm); } - bool requested_help() const { return help_flag; } - - aesni::Mode mode; - aesni::Algorithm algorithm; - std::vector args; + bool exit_with_usage() const { return help_flag; } private: const std::string prog_name; @@ -107,7 +107,7 @@ namespace std::ostream& operator<<(std::ostream& os, const CommandLineParser& cmd_parser) { - return os << "Usage: " << cmd_parser.prog_name << " [OPTIONS...] KEY [IV] SRC_PATH DEST_PATH\n" + return os << "Usage: " << cmd_parser.prog_name << " [OPTION...]\n" << cmd_parser.options << "\n"; } } -- cgit v1.2.3