Add main and user interface
This commit is contained in:
parent
1fb526e711
commit
570b5e45f5
@ -1,4 +1,10 @@
|
||||
set(SOURCES main.cpp crypto.cpp io.cpp utils.cpp)
|
||||
set(SOURCES
|
||||
main.cpp
|
||||
horcrux.cpp
|
||||
crypto.cpp
|
||||
io.cpp
|
||||
utils.cpp
|
||||
)
|
||||
|
||||
add_executable(horcrux ${SOURCES})
|
||||
add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${SOURCES})
|
||||
|
@ -32,17 +32,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
AES256_CBC::AES256_CBC(){
|
||||
encryption_key = utils::generate_random(kKeySize);
|
||||
}
|
||||
AES256_CBC::AES256_CBC(const std::vector<unsigned char>& key){
|
||||
encryption_key = key;
|
||||
}
|
||||
AES256_CBC::AES256_CBC(std::vector<unsigned char>&& key){
|
||||
encryption_key = key;
|
||||
}
|
||||
|
||||
EvpCipherCtx AES256_CBC::init(Cipher::Mode mode,
|
||||
EvpCipherCtx AES256_CBC::init(Mode mode,
|
||||
const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv){
|
||||
if (key.size() != kKeySize){
|
||||
throw std::runtime_error("Wrong key size");
|
||||
@ -52,12 +42,12 @@ EvpCipherCtx AES256_CBC::init(Cipher::Mode mode,
|
||||
}
|
||||
|
||||
EvpCipherCtx ctx;
|
||||
if (mode == Cipher::Mode::kEncrypt){
|
||||
if (mode == Mode::kEncrypt){
|
||||
if (EVP_EncryptInit(ctx.get(), EVP_aes_256_cbc(),
|
||||
(key.data()), (iv.data())) == 0){
|
||||
throw std::runtime_error("EVP_EncryptInit");
|
||||
}
|
||||
} else if (mode == Cipher::Mode::kDecrypt){
|
||||
} else if (mode == Mode::kDecrypt){
|
||||
if (EVP_DecryptInit(ctx.get(), EVP_aes_256_cbc(),
|
||||
(key.data()), (iv.data())) == 0){
|
||||
throw std::runtime_error("EVP_DecryptInit");
|
||||
@ -66,7 +56,7 @@ EvpCipherCtx AES256_CBC::init(Cipher::Mode mode,
|
||||
return ctx;
|
||||
}
|
||||
|
||||
size_t AES256_CBC::process_chunk(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t AES256_CBC::process_chunk(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>::const_iterator begin,
|
||||
std::vector<unsigned char>::const_iterator end,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
@ -78,7 +68,7 @@ size_t AES256_CBC::process_chunk(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
// Make sure ouput is large enough to add encrypted data + padding
|
||||
output.resize(output_offset + chunk_size + kIvSize);
|
||||
}
|
||||
if (mode == Cipher::Mode::kEncrypt) {
|
||||
if (mode == Mode::kEncrypt) {
|
||||
if (1 != EVP_EncryptUpdate(ctx.get(),
|
||||
output.data() + output_offset, &len, &*begin, chunk_size)){
|
||||
throw std::runtime_error("EVP_EncryptUpdate");
|
||||
@ -94,7 +84,7 @@ size_t AES256_CBC::process_chunk(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t AES256_CBC::process_final(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t AES256_CBC::process_final(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
bool resize_in, bool resize_out)
|
||||
{
|
||||
@ -103,7 +93,7 @@ size_t AES256_CBC::process_final(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
// Make sure output is large enough to add the last block
|
||||
output.resize(output_offset + kIvSize);
|
||||
}
|
||||
if (mode == Cipher::Mode::kEncrypt) {
|
||||
if (mode == Mode::kEncrypt) {
|
||||
if (1 != EVP_EncryptFinal_ex(ctx.get(), output.data() + output_offset, &len)){
|
||||
throw std::runtime_error("EVP_EncryptFinal");
|
||||
}
|
||||
@ -117,7 +107,7 @@ size_t AES256_CBC::process_final(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t AES256_CBC::process_all(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t AES256_CBC::process_all(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>::const_iterator begin,
|
||||
std::vector<unsigned char>::const_iterator end,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
@ -130,9 +120,15 @@ size_t AES256_CBC::process_all(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
return len;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> AES256_CBC::process(const std::vector<unsigned char>& inputdata) {
|
||||
if (mode == Mode::kEncrypt)
|
||||
return encrypt(inputdata);
|
||||
else
|
||||
return decrypt(inputdata);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> AES256_CBC::encrypt(const std::vector<unsigned char>& plaintext) {
|
||||
return encrypt(encryption_key, utils::generate_random(kIvSize), plaintext);
|
||||
return encrypt(encryption_key, horcrux::generate_random(kIvSize), plaintext);
|
||||
}
|
||||
std::vector<unsigned char> AES256_CBC::decrypt(const std::vector<unsigned char>& ciphertext) {
|
||||
return decrypt(encryption_key, ciphertext);
|
||||
@ -141,12 +137,12 @@ std::vector<unsigned char> AES256_CBC::decrypt(const std::vector<unsigned char>&
|
||||
std::vector<unsigned char> AES256_CBC::encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& input)
|
||||
{
|
||||
auto ctx = init(Cipher::Mode::kEncrypt, key, iv);
|
||||
auto ctx = init(Mode::kEncrypt, key, iv);
|
||||
|
||||
// Make sure ouput is large enough to contain IV + encrypted data + padding
|
||||
std::vector<unsigned char> output(input.size() + (2 * kIvSize));
|
||||
std::copy(iv.begin(), iv.end(), output.begin());
|
||||
process_all(Cipher::Mode::kEncrypt, ctx, input.begin(), input.end(), output, kIvSize);
|
||||
process_all(Mode::kEncrypt, ctx, input.begin(), input.end(), output, kIvSize);
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -154,8 +150,8 @@ std::vector<unsigned char> AES256_CBC::encrypt(const std::vector<unsigned char>&
|
||||
int AES256_CBC::encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& input, std::vector<unsigned char>& output)
|
||||
{
|
||||
auto ctx = init(Cipher::Mode::kEncrypt, key, iv);
|
||||
process_all(Cipher::Mode::kEncrypt, ctx, input.begin(), input.end(), output, 0);
|
||||
auto ctx = init(Mode::kEncrypt, key, iv);
|
||||
process_all(Mode::kEncrypt, ctx, input.begin(), input.end(), output, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -177,8 +173,8 @@ int AES256_CBC::encrypt(const std::vector<unsigned char>& key, const std::vector
|
||||
int AES256_CBC::decrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& input, std::vector<unsigned char>& output)
|
||||
{
|
||||
auto ctx = init(Cipher::Mode::kDecrypt, key, iv);
|
||||
process_all(Cipher::Mode::kDecrypt, ctx, input.begin(), input.end(), output, 0);
|
||||
auto ctx = init(Mode::kDecrypt, key, iv);
|
||||
process_all(Mode::kDecrypt, ctx, input.begin(), input.end(), output, 0);
|
||||
return 0;
|
||||
}
|
||||
std::vector<unsigned char> AES256_CBC::decrypt(const std::vector<unsigned char>& key,
|
||||
@ -190,9 +186,9 @@ std::vector<unsigned char> AES256_CBC::decrypt(
|
||||
const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator end)
|
||||
{
|
||||
auto ctx = init(Cipher::Mode::kDecrypt, key, iv);
|
||||
auto ctx = init(Mode::kDecrypt, key, iv);
|
||||
std::vector<unsigned char> output;
|
||||
process_all(Cipher::Mode::kDecrypt, ctx, begin, end, output, 0);
|
||||
process_all(Mode::kDecrypt, ctx, begin, end, output, 0);
|
||||
return output;
|
||||
}
|
||||
}; //namespace
|
||||
|
83
src/crypto.h
83
src/crypto.h
@ -4,44 +4,30 @@
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
namespace horcrux {
|
||||
enum class CipherType {AES256_CBC};
|
||||
|
||||
enum class Mode {kEncrypt, kDecrypt};
|
||||
|
||||
class Cipher {
|
||||
protected:
|
||||
Cipher() = delete;
|
||||
Cipher(Mode m) : mode(m) { }
|
||||
Cipher(Mode m, const std::vector<unsigned char>& key) :
|
||||
mode(m), encryption_key(key) {}
|
||||
|
||||
Cipher(Mode m, std::vector<unsigned char>&& key) :
|
||||
mode(m), encryption_key(key) {}
|
||||
|
||||
std::vector<unsigned char> encryption_key;
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
kEncrypt,
|
||||
kDecrypt
|
||||
};
|
||||
const Mode mode;
|
||||
const std::vector<unsigned char>& get_encryption_key() {return encryption_key;}
|
||||
|
||||
virtual std::vector<unsigned char> process(const std::vector<unsigned char>& inputdata) = 0;
|
||||
virtual std::vector<unsigned char> encrypt(const std::vector<unsigned char>& plaintext) = 0;
|
||||
virtual std::vector<unsigned char> decrypt(const std::vector<unsigned char>& ciphertext) = 0;
|
||||
/*
|
||||
virtual std::pair<std::vector<unsigned char>, std::vector<unsigned char>>
|
||||
encrypt_all(std::vector<unsigned char>& plaintext) = 0;
|
||||
|
||||
virtual std::vector<unsigned char>
|
||||
encrypt_all(std::vector<unsigned char>& plaintext,
|
||||
std::ostream);
|
||||
|
||||
virtual std::vector<unsigned char>
|
||||
decrypt_all(std::vector<unsigned char>& ciphertext, std::vector<unsigned char>& key) = 0;
|
||||
|
||||
virtual void encrypt_init(std::vector<unsigned char>& key, std::vector<unsigned char>& iv) = 0;
|
||||
|
||||
virtual void encrypt_chunk() = 0;
|
||||
|
||||
virtual void encrypt_fini() = 0;
|
||||
|
||||
virtual void decrypt_init(std::vector<unsigned char>& key, std::vector<unsigned char>& iv) = 0;
|
||||
|
||||
virtual void decrypt_chunk() = 0;
|
||||
|
||||
virtual void decrypt_fini() = 0;
|
||||
*/
|
||||
};
|
||||
|
||||
class EvpCipherCtx;
|
||||
@ -51,19 +37,27 @@ class AES256_CBC : public Cipher {
|
||||
const size_t kIvSize = 16;
|
||||
|
||||
public:
|
||||
AES256_CBC();
|
||||
AES256_CBC(const std::vector<unsigned char>& key);
|
||||
AES256_CBC(std::vector<unsigned char>&& key);
|
||||
AES256_CBC() : Cipher(Mode::kEncrypt) {
|
||||
encryption_key = horcrux::generate_random(kKeySize);
|
||||
}
|
||||
AES256_CBC(const std::vector<unsigned char>& key) : Cipher(Mode::kDecrypt, key)
|
||||
{
|
||||
if (key.size() != kKeySize)
|
||||
throw std::invalid_argument("Invalid key size");
|
||||
}
|
||||
AES256_CBC(std::vector<unsigned char>&& key) : Cipher(Mode::kDecrypt, key)
|
||||
{
|
||||
if (key.size() != kKeySize)
|
||||
throw std::invalid_argument("Invalid key size");
|
||||
}
|
||||
|
||||
std::vector<unsigned char> process(const std::vector<unsigned char>& inputdata) override;
|
||||
std::vector<unsigned char> encrypt(const std::vector<unsigned char>& plaintext) override;
|
||||
std::vector<unsigned char> decrypt(const std::vector<unsigned char>& ciphertext) override;
|
||||
|
||||
std::vector<unsigned char> encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& input);
|
||||
|
||||
//int encrypt(const std::vector<unsigned char>& key,
|
||||
// const std::vector<unsigned char>& input, std::vector<unsigned char>& output);
|
||||
|
||||
int encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
|
||||
const std::vector<unsigned char>& input, std::vector<unsigned char>& output);
|
||||
|
||||
@ -82,34 +76,25 @@ public:
|
||||
std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator end);
|
||||
|
||||
private:
|
||||
EvpCipherCtx init(Cipher::Mode mode,
|
||||
EvpCipherCtx init(Mode mode,
|
||||
const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv);
|
||||
|
||||
size_t process_chunk(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t process_chunk(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>::const_iterator begin,
|
||||
std::vector<unsigned char>::const_iterator end,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
bool resize_in = true, bool resize_out = true);
|
||||
|
||||
size_t process_final(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t process_final(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
bool resize_in = true, bool resize_out = true);
|
||||
|
||||
size_t process_all(Cipher::Mode mode, EvpCipherCtx& ctx,
|
||||
size_t process_all(Mode mode, EvpCipherCtx& ctx,
|
||||
std::vector<unsigned char>::const_iterator begin,
|
||||
std::vector<unsigned char>::const_iterator end,
|
||||
std::vector<unsigned char>& output, size_t output_offset,
|
||||
bool resize_in = true, bool resize_out = true);
|
||||
};
|
||||
|
||||
static std::unique_ptr<Cipher> createCipher(CipherType type){
|
||||
switch(type){
|
||||
case CipherType::AES256_CBC:
|
||||
return std::make_unique<AES256_CBC>();
|
||||
default:
|
||||
throw std::runtime_error("Unknown cipher");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}; //namespace
|
||||
#endif //HORCRUX_SRC_CRYPTO_H
|
||||
|
82
src/horcrux.cpp
Normal file
82
src/horcrux.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include "horcrux.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace horcrux {
|
||||
|
||||
Horcrux::Horcrux(HorcruxOptions&& opt) : options(opt){ init(); }
|
||||
Horcrux::Horcrux(const HorcruxOptions& opt) : options(opt){ init(); }
|
||||
void Horcrux::init(){
|
||||
if (options.count <= 0){
|
||||
throw std::invalid_argument("Invalid horcrux count");
|
||||
}
|
||||
switch (options.mode){
|
||||
case Mode::kEncrypt:
|
||||
cipher = std::make_unique<AES256_CBC>();
|
||||
input = std::make_unique<FsPlainInput>(options.input[0]);
|
||||
output = std::make_unique<FsCryptoOutput>(options.output, options.count,
|
||||
std::filesystem::path(options.input[0]).filename().string());
|
||||
options.base64_key = to_base64(cipher->get_encryption_key());
|
||||
break;
|
||||
case Mode::kDecrypt:
|
||||
if (options.count != options.input.size())
|
||||
throw std::invalid_argument("Invalid horcrux count");
|
||||
cipher = std::make_unique<AES256_CBC>(from_base64(options.base64_key));
|
||||
input = std::make_unique<FsCryptoInput>(options.input);
|
||||
output = std::make_unique<FsPlainOutput>(options.output);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument("Invalid horcrux mode");
|
||||
}
|
||||
}
|
||||
|
||||
void Horcrux::execute(){
|
||||
if (options.mode == Mode::kEncrypt)
|
||||
output->write(cipher->encrypt(input->read()));
|
||||
else
|
||||
output->write(cipher->decrypt(input->read()));
|
||||
}
|
||||
|
||||
static void print_usage(const std::string& program){
|
||||
std::cout << "Usage:" << std::endl <<
|
||||
"\t\t" << program << " create -n <horcrux count> <input path> <output path>" << std::endl <<
|
||||
"\t\t" << program << " load -k <decryption key> <input files> <output_path>" << std::endl;
|
||||
}
|
||||
|
||||
static void parse_error(const std::string& program, const std::string& error){
|
||||
print_usage(program);
|
||||
throw std::invalid_argument(error);
|
||||
}
|
||||
|
||||
HorcruxOptions parse_arguments(std::vector<std::string>&& arguments){
|
||||
if (arguments.size() < 6){
|
||||
parse_error(std::string(arguments[0]), "Wrong argument number");
|
||||
}
|
||||
HorcruxOptions opt;
|
||||
if (arguments[1] == "create") {
|
||||
if (arguments.size() != 6){
|
||||
parse_error(std::string(arguments[0]), "Wrong argument number");
|
||||
}
|
||||
opt.mode = Mode::kEncrypt;
|
||||
if (arguments[2] != "-n")
|
||||
parse_error(arguments[0], "create: unknown option " + arguments[2]);
|
||||
opt.count = std::stoi(arguments[3]);
|
||||
opt.input.emplace_back(arguments[4]);
|
||||
opt.output = arguments[5];
|
||||
} else if (arguments[1] == "load"){
|
||||
opt.mode = Mode::kDecrypt;
|
||||
if (arguments[2] != "-k")
|
||||
parse_error(arguments[0], "load: unknown option " + arguments[2]);
|
||||
opt.base64_key = arguments[3];
|
||||
opt.input.insert(opt.input.begin(), arguments.begin() + 4, arguments.end() - 1);
|
||||
opt.count = opt.input.size();
|
||||
opt.output = arguments.back();
|
||||
} else {
|
||||
parse_error(arguments[0], "unknown mode: " + arguments[1]);
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
|
||||
|
||||
}; //namespace
|
41
src/horcrux.h
Normal file
41
src/horcrux.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef HORCRUX_HORCRUX_H
|
||||
#define HORCRUX_HORCRUX_H
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "io.h"
|
||||
|
||||
namespace horcrux {
|
||||
|
||||
struct HorcruxOptions {
|
||||
Mode mode;
|
||||
int count;
|
||||
std::vector<std::string> input;
|
||||
std::string output;
|
||||
std::string base64_key;
|
||||
};
|
||||
|
||||
class Horcrux {
|
||||
|
||||
HorcruxOptions options;
|
||||
std::unique_ptr<Cipher> cipher;
|
||||
std::unique_ptr<Input> input;
|
||||
std::unique_ptr<Output> output;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
Horcrux(const HorcruxOptions& opt);
|
||||
Horcrux(HorcruxOptions&& opt);
|
||||
void execute();
|
||||
const Mode& mode() { return options.mode; }
|
||||
const std::string& key() { return options.base64_key; }
|
||||
|
||||
};
|
||||
|
||||
HorcruxOptions parse_arguments(std::vector<std::string>&& arguments);
|
||||
|
||||
}; //namespace
|
||||
#endif //HORCRUX_HORCRUX_H
|
11
src/io.cpp
11
src/io.cpp
@ -1,10 +1,11 @@
|
||||
#include <iostream>
|
||||
#include "io.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace horcrux {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
FsPlainInput::FsPlainInput(const std::string& path) : file_path(path)
|
||||
FsPlainInput::FsPlainInput(const std::string& path) : file_path(fs::absolute(path))
|
||||
{
|
||||
if (fs::status(path).type() != fs::file_type::regular){
|
||||
throw std::invalid_argument("Input is not a regular file");
|
||||
@ -28,7 +29,7 @@ FsCryptoInput::FsCryptoInput(const std::vector<std::string>& filenames)
|
||||
throw std::invalid_argument("No files to decrypt");
|
||||
}
|
||||
for (auto name : filenames){
|
||||
auto path = fs::path{name};
|
||||
auto path = absolute(fs::absolute({name}));
|
||||
if (fs::status(path).type() != fs::file_type::regular){
|
||||
throw std::invalid_argument("Input is not a regular file");
|
||||
}
|
||||
@ -52,7 +53,7 @@ std::vector<unsigned char> FsCryptoInput::read(){
|
||||
}
|
||||
|
||||
FsPlainOutput::FsPlainOutput(const std::string& filename)
|
||||
: file_path(filename)
|
||||
: file_path(fs::absolute(filename))
|
||||
{
|
||||
if (fs::exists(file_path) && fs::status(file_path).type() != fs::file_type::regular){
|
||||
throw std::invalid_argument("Output file is not a regular file");
|
||||
@ -66,7 +67,7 @@ size_t FsPlainOutput::write(const std::vector<unsigned char>& to_write){
|
||||
|
||||
FsCryptoOutput::FsCryptoOutput(const std::string& folder, const int horcrux_num,
|
||||
const std::string& filename, const size_t horcrux_size)
|
||||
: folder_path(folder), base_name(filename),
|
||||
: folder_path(fs::absolute(folder)), base_name(filename),
|
||||
num(horcrux_num), size(horcrux_size)
|
||||
{
|
||||
if (fs::status(folder_path).type() != fs::file_type::directory){
|
||||
@ -84,7 +85,7 @@ size_t FsCryptoOutput::write(const std::vector<unsigned char>& to_write){
|
||||
created_files.clear();
|
||||
size_t data_written{0};
|
||||
for (int i = 0; i < num; ++i){
|
||||
std::string name = base_name + '_' + std::to_string(i) + ".enc";
|
||||
std::string name = base_name + '.' + std::to_string(i) + ".enc";
|
||||
created_files.emplace_back(folder_path / name);
|
||||
f = std::ofstream(created_files.back(),
|
||||
std::ios::binary | std::ios::trunc);
|
||||
|
89
src/main.cpp
89
src/main.cpp
@ -1,69 +1,30 @@
|
||||
#include <string>
|
||||
|
||||
enum RetErr {
|
||||
kOk = 0,
|
||||
kUnknownMode,
|
||||
};
|
||||
|
||||
enum HorcruxMode {
|
||||
kCreate,
|
||||
kLoad
|
||||
};
|
||||
|
||||
|
||||
struct HorcruxOptions {
|
||||
HorcruxMode mode;
|
||||
unsigned int count;
|
||||
std::string key;
|
||||
std::string input;
|
||||
std::string output;
|
||||
};
|
||||
|
||||
//RetErr parse_create_options(std::vector<std::string>& arguments, HorcruxOptions& opt){
|
||||
// opt.mode = kCreate;
|
||||
//}
|
||||
//RetErr parse_load_options(std::vector<std::string>& arguments, HorcruxOptions& opt){
|
||||
// opt.mode = kLoad;
|
||||
//}
|
||||
//
|
||||
//ret_err parse_options(int argc, const char *args[]){
|
||||
// const std::vector<const std:string> arguments;
|
||||
// for (int i = 1; i < argc, ++i){
|
||||
// arguments.push_back(args[i]);
|
||||
// }
|
||||
// horcrux_options options;
|
||||
// if (argc < 1)
|
||||
// return -EINVAL;
|
||||
// const std::string mode(args[1]);
|
||||
// if (mode == "create"){
|
||||
// options.horcrux_mode = horcrux_create;
|
||||
// } else if (mode == "load"){
|
||||
// options.horcrux_mode = horcrux_load;
|
||||
// } else {
|
||||
// return kUnknownMode;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//RetErr horcrux_create(HorcruxOptions& options){
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
#include <iostream>
|
||||
#include "horcrux.h"
|
||||
|
||||
int main(const int argc, const char *argv[]) {
|
||||
HorcruxOptions options;
|
||||
// RetErr ret = parse_arguments(argc, argv);
|
||||
// switch (options.mode){
|
||||
// case kCreate:
|
||||
// ret = horcrux_create(options);
|
||||
// break;
|
||||
// case kLoad:
|
||||
// ret = horcrux_load(options);
|
||||
// break;
|
||||
// default:
|
||||
// std::cout << "Error: Unknown Mode" << std::endl;
|
||||
// break;
|
||||
// }
|
||||
return 0;
|
||||
int ret = -1;
|
||||
std::vector<std::string> arguments;
|
||||
for (int i = 0; i < argc; ++i){
|
||||
arguments.emplace_back(argv[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
horcrux::Horcrux h(horcrux::parse_arguments(std::move(arguments)));
|
||||
h.execute();
|
||||
if (h.mode() == horcrux::Mode::kEncrypt){
|
||||
//print encryption key to stdout
|
||||
std::cout << h.key() << std::endl;
|
||||
}
|
||||
ret = 0;
|
||||
} catch (std::invalid_argument& ex){
|
||||
std::cerr << "Error: Invalid arguments. " << ex.what() << std::endl;
|
||||
} catch (std::runtime_error& ex){
|
||||
std::cerr << "Runtime error: " << ex.what() << std::endl;
|
||||
} catch (std::exception& ex){
|
||||
std::cerr << "Unknown error: " << ex.what() << std::endl;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
std::string utils::to_base64(const std::vector<unsigned char>& binary)
|
||||
std::string horcrux::to_base64(const std::vector<unsigned char>& binary)
|
||||
{
|
||||
using namespace boost::archive::iterators;
|
||||
using It = base64_from_binary<transform_width<std::vector<unsigned char>::const_iterator, 6, 8>>;
|
||||
@ -14,7 +14,7 @@ std::string utils::to_base64(const std::vector<unsigned char>& binary)
|
||||
return base64.append((3 - binary.size() % 3) % 3, '=');
|
||||
}
|
||||
|
||||
std::vector<unsigned char> utils::from_base64(const std::string& base64)
|
||||
std::vector<unsigned char> horcrux::from_base64(const std::string& base64)
|
||||
{
|
||||
using namespace boost::archive::iterators;
|
||||
using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
|
||||
@ -32,7 +32,7 @@ std::vector<unsigned char> utils::from_base64(const std::string& base64)
|
||||
return binary;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> utils::generate_random(const size_t size){
|
||||
std::vector<unsigned char> horcrux::generate_random(const size_t size){
|
||||
std::vector<unsigned char> res(size);
|
||||
if(!RAND_bytes(res.data(), size)){
|
||||
throw std::exception();
|
||||
|
@ -2,8 +2,9 @@
|
||||
#define HORCRUX_SRC_UTILS_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
namespace utils {
|
||||
namespace horcrux {
|
||||
|
||||
std::string to_base64(const std::vector<unsigned char>& binary);
|
||||
std::vector<unsigned char> from_base64(const std::string& base64);
|
||||
|
@ -1,27 +1,29 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "test.h"
|
||||
#include "horcrux.h"
|
||||
|
||||
using namespace horcrux;
|
||||
|
||||
TEST(IntegrationTest, EndToEndEncryptDecrypt){
|
||||
auto buf = generic_read_file(image);
|
||||
|
||||
//Prepare encrypt operation
|
||||
auto in = horcrux::FsPlainInput(image);
|
||||
auto cipher = horcrux::AES256_CBC();
|
||||
auto out = horcrux::FsCryptoOutput(folder, 3);
|
||||
auto in = FsPlainInput(image);
|
||||
auto cipher = AES256_CBC();
|
||||
auto out = FsCryptoOutput(folder, 3);
|
||||
|
||||
// Perform encrypt operation
|
||||
out.write(cipher.encrypt(in.read()));
|
||||
|
||||
//Prepare decrypt operation
|
||||
auto in2 = horcrux::FsCryptoInput(get_created_filenames(out));
|
||||
auto in2 = FsCryptoInput(get_created_filenames(out));
|
||||
//Perform decrypt operation
|
||||
auto buf2 = cipher.decrypt(in2.read());
|
||||
|
||||
//check outcome
|
||||
EXPECT_EQ(buf, buf2);
|
||||
|
||||
auto out2 = horcrux::FsPlainOutput(noexist);
|
||||
auto out2 = FsPlainOutput(noexist);
|
||||
out2.write(cipher.decrypt(in2.read()));
|
||||
|
||||
auto buf3 = generic_read_file(noexist);
|
||||
@ -30,3 +32,97 @@ TEST(IntegrationTest, EndToEndEncryptDecrypt){
|
||||
delete_created_files(out);
|
||||
std::filesystem::remove(noexist);
|
||||
}
|
||||
|
||||
TEST(IntegrationTest, HorcruxOptions){
|
||||
HorcruxOptions options {
|
||||
.mode = Mode::kEncrypt,
|
||||
.count = -1,
|
||||
.input = {noexist},
|
||||
.output = {image}
|
||||
};
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.count = 1;
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.input = {image};
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.output = {folder};
|
||||
options.count = 0;
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.count = 2;
|
||||
EXPECT_NO_THROW(Horcrux {options});
|
||||
options.mode = Mode::kDecrypt;
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.input = {image, text};
|
||||
options.count = 1;
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.output = {noexist};
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.count = 2;
|
||||
EXPECT_THROW(Horcrux {options}, std::invalid_argument);
|
||||
options.base64_key = to_base64(generate_random(32));
|
||||
EXPECT_NO_THROW(Horcrux {options});
|
||||
}
|
||||
TEST(IntegrationTest, HorcruxEncryptiDecrypt) {
|
||||
HorcruxOptions options {
|
||||
.mode = Mode::kEncrypt,
|
||||
.count = 3,
|
||||
.input = {image},
|
||||
.output = {folder}
|
||||
};
|
||||
Horcrux enc{options};
|
||||
|
||||
enc.execute();
|
||||
auto key = enc.key();
|
||||
|
||||
HorcruxOptions options2 {
|
||||
.mode = Mode::kDecrypt,
|
||||
.count = 3,
|
||||
.input = {get_encrypted_files(folder, image)},
|
||||
.output = {noexist},
|
||||
.base64_key = key
|
||||
};
|
||||
|
||||
Horcrux dec{options2};
|
||||
dec.execute();
|
||||
|
||||
//Compare input and ouput files
|
||||
EXPECT_EQ(generic_read_file(image), generic_read_file(noexist));
|
||||
std::filesystem::remove(noexist);
|
||||
std::for_each(options2.input.begin(), options2.input.end(), [](auto& p){
|
||||
std::filesystem::remove(p);});
|
||||
}
|
||||
TEST(IntegrationTest, arguments){
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "create", "-n", "4", "input_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "pippo", "-n", "4", "input_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "create", "-n", "4", "input_file", "output_file", "garbage"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "create", "-h", "4", "input_file", "output_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "create", "-n", "boh", "input_file", "output_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_NO_THROW(
|
||||
parse_arguments({"horcrux", "create", "-n", "4", "input_file", "output_file"}));
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "load", "-n", "4", "input_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "load", "-k", "lshgflushlgkjusghl", "input_file"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "load", "-r", "lshgflushlgkjusghl", "input", "input", "output"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_THROW(
|
||||
parse_arguments({"horcrux", "load", "-k", "lshgflushlgkjusghl", "input"}),
|
||||
std::invalid_argument);
|
||||
EXPECT_NO_THROW(
|
||||
parse_arguments({"horcrux", "load", "-k", "lshgflushlgkjusghl", "input", "output"}));
|
||||
EXPECT_NO_THROW(
|
||||
parse_arguments({"horcrux", "load", "-k", "lshgflushlgkjusghl", "input", "input", "output"}));
|
||||
}
|
||||
|
@ -171,5 +171,6 @@ TEST(IoTest, CryptoToPlain){
|
||||
//check the outcome
|
||||
auto buf2 = generic_read_file(noexist);
|
||||
EXPECT_EQ(buf, buf2);
|
||||
delete_created_files(out_test);
|
||||
std::filesystem::remove(noexist);
|
||||
}
|
||||
|
@ -1,4 +1,38 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "test.h"
|
||||
|
||||
/* Utility functions */
|
||||
std::vector<unsigned char> generic_read_file(const std::string& filename){
|
||||
auto ifstream = std::ifstream{filename, std::ios::binary};
|
||||
auto path = std::filesystem::path{filename};
|
||||
auto size = std::filesystem::file_size(path);
|
||||
std::vector<unsigned char> buf(size);
|
||||
ifstream.read(reinterpret_cast<char*>(buf.data()), size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_created_filenames(const horcrux::FsCryptoOutput& out){
|
||||
std::vector<std::string> result(out.created_files.size());
|
||||
transform(out.created_files.begin(), out.created_files.end(), result.begin(),
|
||||
[](auto path){return path.string();});
|
||||
return result;
|
||||
}
|
||||
void delete_created_files(const horcrux::FsCryptoOutput& out){
|
||||
std::for_each(out.created_files.begin(), out.created_files.end(),
|
||||
[](auto f){std::filesystem::remove(f);});
|
||||
}
|
||||
|
||||
std::vector<std::string> get_encrypted_files(const std::string& folder, const std::string& basename) {
|
||||
std::vector<std::string> result;
|
||||
for (auto& p: std::filesystem::directory_iterator(folder)){
|
||||
if (p.path().string().starts_with(basename) &&
|
||||
p.path().string().ends_with(".enc"))
|
||||
result.push_back(p.path().string());
|
||||
}
|
||||
std::sort(result.begin(), result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
25
test/test.h
25
test/test.h
@ -1,6 +1,7 @@
|
||||
#ifndef HORCRUX_TEST_TEST_H
|
||||
#define HORCRUX_TEST_TEST_H
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include "io.h"
|
||||
#include "crypto.h"
|
||||
|
||||
@ -15,25 +16,13 @@ const std::string empty{TEST_WORK_DIR "/empty"};
|
||||
const std::string text{TEST_WORK_DIR "/test.txt"};
|
||||
const std::string image{TEST_WORK_DIR "/mangoni.jpg"};
|
||||
|
||||
static std::vector<unsigned char> generic_read_file(const std::string& filename){
|
||||
auto ifstream = std::ifstream{filename, std::ios::binary};
|
||||
auto path = std::filesystem::path{filename};
|
||||
auto size = std::filesystem::file_size(path);
|
||||
std::vector<unsigned char> buf(size);
|
||||
ifstream.read(reinterpret_cast<char*>(buf.data()), size);
|
||||
return buf;
|
||||
}
|
||||
std::vector<unsigned char> generic_read_file(const std::string& filename);
|
||||
|
||||
static std::vector<std::string> get_created_filenames(const horcrux::FsCryptoOutput& out){
|
||||
std::vector<std::string> result(out.created_files.size());
|
||||
transform(out.created_files.begin(), out.created_files.end(), result.begin(),
|
||||
[](auto path){return path.string();});
|
||||
return result;
|
||||
}
|
||||
static void delete_created_files(const horcrux::FsCryptoOutput& out){
|
||||
std::for_each(out.created_files.begin(), out.created_files.end(),
|
||||
[](auto f){std::filesystem::remove(f);});
|
||||
}
|
||||
std::vector<std::string> get_created_filenames(const horcrux::FsCryptoOutput& out);
|
||||
|
||||
void delete_created_files(const horcrux::FsCryptoOutput& out);
|
||||
|
||||
std::vector<std::string> get_encrypted_files(const std::string& folder, const std::string& basename);
|
||||
|
||||
/* Crypto Test utils */
|
||||
|
||||
|
@ -16,30 +16,30 @@ const std::string test4_str = "mi e' entrata una bruschetta nell'occhio";
|
||||
const std::string test4_base64 = "bWkgZScgZW50cmF0YSB1bmEgYnJ1c2NoZXR0YSBuZWxsJ29jY2hpbw==";
|
||||
|
||||
TEST(utilTests, to_base64Test){
|
||||
EXPECT_EQ(test1_base64, utils::to_base64(std::vector<unsigned char>(test1_str.begin(), test1_str.end())));
|
||||
EXPECT_EQ(test2_base64, utils::to_base64(std::vector<unsigned char>(test2_str.begin(), test2_str.end())));
|
||||
EXPECT_EQ(test3_base64, utils::to_base64(std::vector<unsigned char>(test3_str.begin(), test3_str.end())));
|
||||
EXPECT_EQ(test4_base64, utils::to_base64(std::vector<unsigned char>(test4_str.begin(), test4_str.end())));
|
||||
EXPECT_EQ(test1_base64, horcrux::to_base64(std::vector<unsigned char>(test1_str.begin(), test1_str.end())));
|
||||
EXPECT_EQ(test2_base64, horcrux::to_base64(std::vector<unsigned char>(test2_str.begin(), test2_str.end())));
|
||||
EXPECT_EQ(test3_base64, horcrux::to_base64(std::vector<unsigned char>(test3_str.begin(), test3_str.end())));
|
||||
EXPECT_EQ(test4_base64, horcrux::to_base64(std::vector<unsigned char>(test4_str.begin(), test4_str.end())));
|
||||
}
|
||||
|
||||
TEST(utilTests, from_base64Test){
|
||||
auto result = utils::from_base64(test1_base64);
|
||||
auto result = horcrux::from_base64(test1_base64);
|
||||
EXPECT_EQ(test1_str, std::string(result.begin(), result.end()));
|
||||
|
||||
result = utils::from_base64(test2_base64);
|
||||
result = horcrux::from_base64(test2_base64);
|
||||
EXPECT_EQ(test2_str, std::string(result.begin(), result.end()));
|
||||
|
||||
result = utils::from_base64(test3_base64);
|
||||
result = horcrux::from_base64(test3_base64);
|
||||
EXPECT_EQ(test3_str, std::string(result.begin(), result.end()));
|
||||
|
||||
result = utils::from_base64(test4_base64);
|
||||
result = horcrux::from_base64(test4_base64);
|
||||
EXPECT_EQ(test4_str, std::string(result.begin(), result.end()));
|
||||
}
|
||||
|
||||
TEST(utilTests, generate_random){
|
||||
EXPECT_NE(utils::generate_random(32), utils::generate_random(32));
|
||||
EXPECT_NE(utils::generate_random(16), utils::generate_random(16));
|
||||
EXPECT_NE(utils::generate_random(8), utils::generate_random(8));
|
||||
EXPECT_NE(utils::generate_random(1), utils::generate_random(1));
|
||||
EXPECT_EQ(utils::generate_random(0), utils::generate_random(0));
|
||||
EXPECT_NE(horcrux::generate_random(32), horcrux::generate_random(32));
|
||||
EXPECT_NE(horcrux::generate_random(16), horcrux::generate_random(16));
|
||||
EXPECT_NE(horcrux::generate_random(8), horcrux::generate_random(8));
|
||||
EXPECT_NE(horcrux::generate_random(1), horcrux::generate_random(1));
|
||||
EXPECT_EQ(horcrux::generate_random(0), horcrux::generate_random(0));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user