Initial commit

Base project structure
This commit is contained in:
Michele Rodolfi 2020-12-11 12:38:02 +01:00
commit db5dfcaa85
14 changed files with 447 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

48
CMakeLists.txt Normal file
View File

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.19)
project(CubbitTestProject)
set(CMAKE_CXX_STANDARD 20)
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
# Now simply link against gtest or gtest_main as needed. Eg
#add_executable(example example.cpp)
#target_link_libraries(example gtest_main)
#add_test(NAME example_test COMMAND example)
enable_testing()
include_directories(src)
add_subdirectory(src)
add_subdirectory(test)
#add_subdirectory(lib/googletest)

15
CMakeLists.txt.in Normal file
View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

64
scripts/aes256.sh Executable file
View File

@ -0,0 +1,64 @@
#!/bin/bash
usage() {
echo "Usage: $0 [-h] [-e | -d] [-b] -k key -i iv"
echo "Reads from stdin and encrypts or decripts to stdout."
echo "key and iv must be provided as arguments."
echo " -h print this summary"
echo " -e encode mode (default)"
echo " -d decode mode"
echo " -k key specify 32 bytes encryption key"
echo " -k iv specify 16 bytes initialization vector"
exit 1
}
#defaults
OPENSSL_ENC=-e
optstring=":edbk:i:h"
while getopts ${optstring} arg; do
case ${arg} in
e)
#encode
OPENSSL_ENC=-e
;;
d)
#decode
OPENSSL_ENC=-d
;;
b)
#base64
OPENSSL_BASE64=-a
;;
k)
#encryption key
if [[ "${#OPTARG}" != 32 ]]; then
echo Please insert a 32 bytes key
exit 1
fi
OPENSSL_KEY=$(echo -n ${OPTARG} | xxd -u -c 32 -ps)
;;
i)
#initialization vector
if [[ "${#OPTARG}" != 16 ]]; then
echo Please insert a 16 bytes initialization vector
exit 1
fi
OPENSSL_IV=$(echo -n ${OPTARG} | xxd -u -c 32 -ps)
;;
h)
usage
;;
*)
echo Invalid option: -${OPTARG}.
usage
;;
esac
done
[[ -z $OPENSSL_KEY ]] && echo Please insert a 32 bytes key && exit 1
[[ -z $OPENSSL_IV ]] && echo Please insert a 16 bytes initialization vector && exit 1
while read line; do
echo -n $line | openssl enc -aes-256-cbc $OPENSSL_ENC $OPENSSL_BASE64 -K $OPENSSL_KEY -iv $OPENSSL_IV
done

10
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
set(SOURCES main.cpp crypto.cpp utils.cpp)
add_executable(horcrux ${SOURCES})
add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${SOURCES})
find_package(OpenSSL 1.1 REQUIRED)
message("Found OpenSSL Version ${OPENSSL_VERSION}")
target_link_libraries(horcrux OpenSSL::Crypto)
target_link_libraries(${CMAKE_PROJECT_NAME}_lib OpenSSL::Crypto)

69
src/crypto.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <string>
#include <vector>
#include <exception>
#include <memory>
#include <istream>
#include <ostream>
#include <openssl/evp.h>
#include "crypto.h"
class EvpCipherCtx {
EVP_CIPHER_CTX *ptr;
public:
EvpCipherCtx(){
ptr = EVP_CIPHER_CTX_new();
}
~EvpCipherCtx(){
EVP_CIPHER_CTX_free(ptr);
}
EVP_CIPHER_CTX* get(){
return ptr;
}
};
int AES256::encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input, const size_t input_len,
std::vector<unsigned char>& output, size_t& output_len)
{
//auto ctx = std::unique_ptr<EVP_CIPHER_CTX>(EVP_CIPHER_CTX_new());
EvpCipherCtx ctx;
if (EVP_EncryptInit(ctx.get(), EVP_aes_256_cbc(),
(key.data()), (iv.data())) == 0){
throw std::exception();
}
int len;
output.reserve(input.size() + block_len);
if (1 != EVP_EncryptUpdate(ctx.get(),
(output.data()), &len, (input.data()), input.size())){
throw std::exception();
}
output_len = len;
if (1 != EVP_EncryptFinal_ex(ctx.get(), (output.data()) + len, &len)){
throw std::exception();
}
output_len += len;
output.resize(output_len);
return 0;
}
int AES256::encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
std::istream input, const size_t input_len,
std::ostream output, size_t& output_len){
auto inbuf = std::vector<unsigned char>(input_len);
auto outbuf = std::vector<unsigned char>(input_len + 16);
input.read(reinterpret_cast<char*>(inbuf.data()), input_len);
encrypt(key, iv, inbuf, input_len, outbuf, output_len);
output.write(reinterpret_cast<char*>(outbuf.data()), output_len);
return 0;
}

19
src/crypto.h Normal file
View File

@ -0,0 +1,19 @@
#include <vector>
#include <string>
#include <cstddef>
class AES256 {
unsigned char key[256];
unsigned char iv[128];
const size_t block_len = 16;
public:
int encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input, const size_t input_len,
std::vector<unsigned char>& output, size_t& output_len);
int encrypt(const std::vector<unsigned char>& key, const std::vector<unsigned char>& iv,
std::istream input, const size_t input_len,
std::ostream output, size_t& output_len);
};

69
src/main.cpp Normal file
View File

@ -0,0 +1,69 @@
#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){
//
//
//}
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;
}

41
src/utils.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <openssl/rand.h>
#include "utils.h"
std::string utils::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>>;
auto base64 = std::string(It(binary.begin()), It(binary.end()));
// Add padding.
return base64.append((3 - binary.size() % 3) % 3, '=');
}
std::vector<unsigned char> utils::from_base64(const std::string& base64)
{
using namespace boost::archive::iterators;
using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
auto binary = std::vector<unsigned char>(It(base64.begin()), It(base64.end()));
// Remove padding.
auto length = base64.size();
if(binary.size() > 2 && base64[length - 1] == '=' && base64[length - 2] == '=')
{
binary.erase(binary.end() - 2, binary.end());
}
else if(binary.size() > 1 && base64[length - 1] == '=')
{
binary.erase(binary.end() - 1, binary.end());
}
return binary;
}
std::vector<unsigned char> utils::generate_random(const size_t size){
std::vector<unsigned char> res(size);
if(!RAND_bytes(res.data(), size)){
throw std::exception();
}
return res;
}

10
src/utils.h Normal file
View File

@ -0,0 +1,10 @@
#include <string>
#include <vector>
namespace utils {
std::string to_base64(const std::vector<unsigned char>& binary);
std::vector<unsigned char> from_base64(const std::string& base64);
std::vector<unsigned char> generate_random(const size_t buf_len);
}

7
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
set(BINARY ${CMAKE_PROJECT_NAME}_test)
add_executable(${BINARY} main.cpp crypto-test.cpp utils-test.cpp)
add_test(NAME test COMMAND ${BINARY})
target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest)

43
test/crypto-test.cpp Normal file
View File

@ -0,0 +1,43 @@
#include <string>
#include "gtest/gtest.h"
#include "utils.h"
#include "crypto.h"
typedef std::basic_string<unsigned char> ustring;
std::vector<std::byte> string_to_bytes(const std::string& str){
std::vector<std::byte> out;
transform(str.begin(), str.end(), std::back_inserter(out), [](auto c){return static_cast<std::byte>(c);});
return out;
}
/* test command:
echo "ditemi perche' se la mucca fa mu il merlo non fa me" |
scripts/aes256.sh -k 0123456789ABCDEF0123456789ABCDEF -i 0123456789ABCDEF |
xxd -i
*/
const std::string test1_str = "ditemi perche' se la mucca fa mu il merlo non fa me";
const std::string test1_key = "0123456789ABCDEF0123456789ABCDEF";
const std::string test1_iv = "0123456789ABCDEF";
const std::vector<unsigned char> test1_enc {
0x4c, 0x17, 0x6e, 0x6d, 0xd2, 0x83, 0x51, 0x52, 0xfc, 0x5d, 0xbe, 0x0f,
0x1b, 0xcf, 0x86, 0xef, 0x73, 0x91, 0x58, 0xc4, 0xdd, 0x1b, 0x09, 0x3d,
0x77, 0xe0, 0x78, 0x5d, 0x21, 0xfe, 0x59, 0x9c, 0xb2, 0x12, 0xa6, 0x81,
0x12, 0x96, 0x50, 0xd6, 0x5c, 0xe2, 0xc1, 0x99, 0xe3, 0x38, 0x39, 0x8e,
0x55, 0xd2, 0x04, 0x73, 0x16, 0x39, 0xc7, 0x6a, 0xd3, 0x61, 0x2c, 0x22,
0x59, 0x25, 0xa6, 0x20 };
TEST(encryptTest, test1){
const std::vector<unsigned char> input(test1_str.begin(), test1_str.end());
size_t output_len = input.size() + 16;
std::vector<unsigned char> output(output_len);
const std::vector<unsigned char> key(test1_key.begin(), test1_key.end());
const std::vector<unsigned char> iv(test1_iv.begin(), test1_iv.end());
AES256 a;
a.encrypt(key, iv, input, input.size(), output, output_len);
EXPECT_EQ(test1_enc, output);
}

6
test/main.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "gtest/gtest.h"
int main(int argc, char *argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

45
test/utils-test.cpp Normal file
View File

@ -0,0 +1,45 @@
#include <string>
#include "gtest/gtest.h"
#include "utils.h"
const std::string test1_str = "sei proprio un sandrone";
const std::string test1_base64 = "c2VpIHByb3ByaW8gdW4gc2FuZHJvbmU=";
const std::string test2_str = "catopleba io ti dono le mie tepa";
const std::string test2_base64 = "Y2F0b3BsZWJhIGlvIHRpIGRvbm8gbGUgbWllIHRlcGE=";
const std::string test3_str = "il pene mi da' si' la moto, ma la moto non da' pene";
const std::string test3_base64 = "aWwgcGVuZSBtaSBkYScgc2knIGxhIG1vdG8sIG1hIGxhIG1vdG8gbm9uIGRhJyBwZW5l";
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())));
}
TEST(utilTests, from_base64Test){
auto result = utils::from_base64(test1_base64);
EXPECT_EQ(test1_str, std::string(result.begin(), result.end()));
result = utils::from_base64(test2_base64);
EXPECT_EQ(test2_str, std::string(result.begin(), result.end()));
result = utils::from_base64(test3_base64);
EXPECT_EQ(test3_str, std::string(result.begin(), result.end()));
result = utils::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));
}