Add main and user interface

This commit is contained in:
Michele Rodolfi 2020-12-12 22:19:10 +01:00
parent 1fb526e711
commit 570b5e45f5
14 changed files with 379 additions and 186 deletions

View File

@ -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})

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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"}));
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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));
}