New directory structure for libghettocrypt

This commit is contained in:
Leonetienne
2022-05-16 21:43:22 +02:00
parent 9772c5fcf8
commit ae276e49af
38 changed files with 19406 additions and 1721 deletions

View File

@@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.16)
project(GCrypt)
###################
# Library project #
###################
set(CMAKE_CXX_STANDARD 17)
FILE(GLOB main_src src/*.cpp)
add_library(${PROJECT_NAME}
${main_src}
)
target_include_directories(${PROJECT_NAME} PRIVATE
include
)
#########
# Tests #
#########
FILE(GLOB test_src test/*.cpp)
add_executable(test
test/Catch2.h
${test_src}
)
target_link_libraries(test ${PROJECT_NAME})
target_include_directories(test PRIVATE
include
)
##############
# Executable #
##############
FILE(GLOB exec_src exec/*.cpp)
add_executable(exec
${exec_src}
)
target_link_libraries(exec ${PROJECT_NAME})
target_include_directories(exec PRIVATE
include
${eule_include}
)

View File

@@ -1,41 +0,0 @@
#pragma once
#include "Feistel.h"
#include "Flexblock.h"
namespace GhettoCipher
{
/** Class to apply a block cipher to messages of arbitrary length in a distributed manner
*/
class Cipher
{
public:
explicit Cipher(const Block& key);
explicit Cipher(const std::string& password);
Cipher(const Cipher& other) = delete;
Cipher(Cipher&& other) noexcept = delete;
~Cipher();
//! Will set the key
void SetKey(const Block& key);
//! Will set the key from a password
void SetPassword(const std::string& password);
//! Will encipher a flexblock of data
Flexblock Encipher(const Flexblock& data, bool printProgress = false) const;
//! Will decipher a flexblock of data
Flexblock Decipher(const Flexblock& data, bool printProgress = false) const;
private:
Block key;
//! Will zero the memory used by the key
void ZeroKeyMemory();
// Initial value for cipher block chaining
Block initializationVector;
};
}

View File

@@ -1,11 +0,0 @@
#pragma once
#include <cstddef>
namespace GhettoCipher
{
// MUST BE A POWER OF 2 > 4
constexpr std::size_t BLOCK_SIZE = 512;
// MUST BE > 2
constexpr std::size_t N_ROUNDS = 64;
}

1
GhettoCrypt/doxygen/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build/

2579
GhettoCrypt/doxygen/doxyfig Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
# Copy repository readme here to be used as a cover page
tail ../readme.md -n +2 > index.md
# Run doxygen
doxygen doxyfig
# Cleanup index.md
rm -f index.md

48
GhettoCrypt/exec/main.cpp Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <iostream>
#include <GhettoCryptWrapper.h>
#include <SecureBitset.h>
#include <Util.h>
#include <InitializationVector.h>
using namespace GhettoCipher;
void ExampleString()
{
std::cout << "Example on how to encrypt & decrypt a string:" << std::endl;
// Get some string
const std::string input = "I am a super secret message!";
std::cout << input << std::endl;
// Encrypt
const std::string encrypted = GhettoCryptWrapper::EncryptString(input, "password1");
std::cout << encrypted << std::endl;
// Decrypt
const std::string decrypted = GhettoCryptWrapper::DecryptString(encrypted, "password1");
std::cout << decrypted << std::endl;
return;
}
void ExampleFiles()
{
std::cout << "Example on how to encrypt & decrypt any file:" << std::endl;
// Encrypt
GhettoCryptWrapper::EncryptFile("main.cpp", "main.cpp.crypt", "password1");
// Decrypt
GhettoCryptWrapper::DecryptFile("main.cpp.crypt", "main.cpp.clear", "password1");
return;
}
int main()
{
ExampleString();
//ExampleFiles();
return 0;
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "Feistel.h"
#include "Flexblock.h"
namespace GhettoCipher {
/** Class to apply a block cipher to messages of arbitrary length in a distributed manner
*/
class Cipher {
public:
explicit Cipher(const Block& key);
explicit Cipher(const std::string& password);
Cipher(const Cipher& other) = delete;
Cipher(Cipher&& other) noexcept = delete;
~Cipher();
//! Will set the key
void SetKey(const Block& key);
//! Will set the key from a password
void SetPassword(const std::string& password);
//! Will encipher a flexblock of data
Flexblock Encipher(const Flexblock& data, bool printProgress = false) const;
//! Will decipher a flexblock of data
Flexblock Decipher(const Flexblock& data, bool printProgress = false) const;
private:
Block key;
//! Will zero the memory used by the key
void ZeroKeyMemory();
// Initial value for cipher block chaining
Block initializationVector;
};
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include <cstddef>
namespace GhettoCipher {
// MUST BE A POWER OF 2 > 4
constexpr std::size_t BLOCK_SIZE = 512;
// MUST BE > 2
constexpr std::size_t N_ROUNDS = 64;
}

17965
GhettoCrypt/test/Catch2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
#include "CppUnitTest.h"
#include "../GhettoCrypt/Cipher.h"
#include "../GhettoCrypt/Util.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace GhettoCipher;
// THESE TESTS ASSUME BLOCK_SIZE == 512
namespace SimpleTests
{
TEST_CLASS(EncryptEqualsDecrypt)
{
public:
// Tests that encrypting a message of exactly BLOCK_SIZE yields the exact message back
TEST_METHOD(SingleBlock_NoPadding)
{
// Instanciate our cipher and supply a key
const Block key = PasswordToKey("1234");
const Cipher cipher(key);
// Recode the ascii-string to bits
const Flexblock cleartext_bits =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100010000001011100010010001101111100100101100010001"
"0000011110010110111010110110111110011110011010001100100111110101";
// Encrypt our cleartext bits
const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
// Decipher it again
const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits);
// Assert that the decrypted text equals the plaintext
Assert::AreEqual(
cleartext_bits,
decryptedBits
);
}
// Tests that encrypting a message of less than BLOCK_SIZE yields the exact message plus zero-padding back
TEST_METHOD(SingleBlock_Padding)
{
// Instanciate our cipher and supply a key
const Block key = PasswordToKey("1234");
const Cipher cipher(key);
// Recode the ascii-string to bits
const Flexblock cleartext_bits =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100";
const Flexblock cleartext_bits_EXPECTED_RESULT =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000";
// Encrypt our cleartext bits
const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
// Decipher it again
const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits);
// Assert that the decrypted text equals the plaintext
Assert::AreEqual(
cleartext_bits_EXPECTED_RESULT,
decryptedBits
);
}
// Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks
TEST_METHOD(MultiBlock_NoPadding)
{
// Instanciate our cipher and supply a key
const Block key = PasswordToKey("1234");
const Cipher cipher(key);
// Recode the ascii-string to bits
const Flexblock cleartext_bits =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100010000001011100010010001101111100100101100010001"
"0000011110010110111010110110111110011110011010001100100111110101"
"1000010010000000000100101011110001000101101101100000010011111011"
"1011111010110100100111100111110011100001111101111110000110001100"
"0001000111000111101110000111011011101010100010100101100111010100"
"0101111110110010110000111111011001101110101101100100100011000100"
"1000110010101001000100001001101000011111101011111100100000100101"
"1100001100111001011111001101000111011101011101000110010110110110"
"0111001010011010010000010110000110010101101100101110111100100011"
"0010111110011100010100000101100101110101101011110100100000110110"
"1001101110101001001111111000010100011100100000101000111101101111"
"0101111011110001101010111010001000111010101111001101100100100100"
"1110110111001100011010110000101000011001011100101100111101110000"
"1010101111011110000111011011011110000111010110110111111010101010"
"0111100101111001010111101000001010100000111010111100111011111001"
"0110111000000110100011011100101101010101101000010010011111100100"
"0010111000001011101110000110010011101001111010100111110111110101"
"1110111000000000101011000100101010000110110111101010011001111010"
"1101011110001110000011010111001100001100101000000101000101000010"
"0101000011011111010010110010000010101100001110011000110111110111"
"1110010101011110111001100010110101101011100111100011101010001011"
"0101110010100110101100111100010000111101111100000111000110110110"
"1001100111000000011010100000011101011000010010011010001011110000"
"1100100111111001001000011100110000011110001100000000010000001001"
"1110000000110010000010011010100011011011000000000111110000110111"
"0101110011001101010110010100011001110110000110010001100110011111";
// Encrypt our cleartext bits
const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
// Decipher it again
const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits);
// Assert that the decrypted text equals the plaintext
Assert::AreEqual(
cleartext_bits,
decryptedBits
);
}
// Tests that a decrypted ciphertext equals its plaintrext version, using a cleartext that requires A LOT of blocks
TEST_METHOD(MultiBlock_Padding)
{
// Instanciate our cipher and supply a key
const Block key = PasswordToKey("1234");
const Cipher cipher(key);
// Recode the ascii-string to bits
const Flexblock cleartext_bits =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100010000001011100010010001101111100100101100010001"
"0000011110010110111010110110111110011110011010001100100111110101"
"1000010010000000000100101011110001000101101101100000010011111011"
"1011111010110100100111100111110011100001111101111110000110001100"
"0001000111000111101110000111011011101010100010100101100111010100"
"0101111110110010110000111111011001101110101101100100100011000100"
"1000110010101001000100001001101000011111101011111100100000100101"
"1100001100111001011111001101000111011101011101000110010110110110"
"0111001010011010010000010110000110010101101100101110111100100011"
"0010111110011100010100000101100101110101101011110100100000110110"
"1001101110101001001111111000010100011100100000101000111101101111"
"0101111011110001101010111010001000111010101111001101100100100100"
"1110110111001100011010110000101000011001011100101100111101110000"
"1010101111011110000111011011011110000111010110110111111010101010"
"0111100101111001010111101000001010100000111010111100111011111001"
"0110111000000110100011011100101101010101101000010010011111100100"
"0010111000001011101110000110010011101001111010100111110111110101"
"1110111000000000101011000100101010000110110111101010011001111010"
"1101011110001110000011010111001100001100101000000101000101000010"
"0101000011011111010010110010000010101100001110011000110111110111"
"1110010101011110111001100010110101101011100111100011101010001011"
"0101110010100110101100111100010000111101111100000111000110110110"
"1001100111000000011010100000011101011000010010011010001011110000"
"1100100111111001001000011100110000011110001100000000010000001001"
"11100000001100100000100110101000110110110000000001111100001";
const Flexblock cleartext_bits_EXPECTED_RESULT =
"1011110011010110000010110001111000111010111101001010100100011101"
"0101110101010010100000110100001000011000111010001001110101111111"
"1110110101100101110001010101011110001010000010111110011011010111"
"1100110100111000000011100101010100110010001110010011000010111001"
"0000010000010000011001111010011110111001000000000110101000110001"
"0110111110110110100000010100000011010001000011100100111001001011"
"1101100100000100010000001011100010010001101111100100101100010001"
"0000011110010110111010110110111110011110011010001100100111110101"
"1000010010000000000100101011110001000101101101100000010011111011"
"1011111010110100100111100111110011100001111101111110000110001100"
"0001000111000111101110000111011011101010100010100101100111010100"
"0101111110110010110000111111011001101110101101100100100011000100"
"1000110010101001000100001001101000011111101011111100100000100101"
"1100001100111001011111001101000111011101011101000110010110110110"
"0111001010011010010000010110000110010101101100101110111100100011"
"0010111110011100010100000101100101110101101011110100100000110110"
"1001101110101001001111111000010100011100100000101000111101101111"
"0101111011110001101010111010001000111010101111001101100100100100"
"1110110111001100011010110000101000011001011100101100111101110000"
"1010101111011110000111011011011110000111010110110111111010101010"
"0111100101111001010111101000001010100000111010111100111011111001"
"0110111000000110100011011100101101010101101000010010011111100100"
"0010111000001011101110000110010011101001111010100111110111110101"
"1110111000000000101011000100101010000110110111101010011001111010"
"1101011110001110000011010111001100001100101000000101000101000010"
"0101000011011111010010110010000010101100001110011000110111110111"
"1110010101011110111001100010110101101011100111100011101010001011"
"0101110010100110101100111100010000111101111100000111000110110110"
"1001100111000000011010100000011101011000010010011010001011110000"
"1100100111111001001000011100110000011110001100000000010000001001"
"1110000000110010000010011010100011011011000000000111110000100000"
"0000000000000000000000000000000000000000000000000000000000000000";
// Encrypt our cleartext bits
const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits);
// Decipher it again
const Flexblock decryptedBits = cipher.Decipher(ciphertext_bits);
// Assert that the decrypted text equals the plaintext
Assert::AreEqual(
cleartext_bits_EXPECTED_RESULT,
decryptedBits
);
}
};
}

View File

@@ -0,0 +1,81 @@
#include "CppUnitTest.h"
#include "../GhettoCrypt/GhettoCryptWrapper.h"
#include "../GhettoCrypt/Flexblock.h"
#include "../GhettoCrypt/Util.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace GhettoCipher;
namespace SimpleTests
{
TEST_CLASS(GCWrapper)
{
public:
// Tests that encrypting and decrypting strings using the wrapper works.
// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated.
TEST_METHOD(String)
{
// Setup
const std::string plaintext = "Hello, World!";
const std::string password = "Der Affe will Zucker";
std::string ciphertext;
std::string decrypted;
// Encryption
{
ciphertext = GhettoCryptWrapper::EncryptString(plaintext, password);
}
// Decryption
{
decrypted = GhettoCryptWrapper::DecryptString(ciphertext, password);
}
// Assertion
Assert::AreEqual(
plaintext,
decrypted
);
}
// Tests that encrypting and decrypting files using the wrapper works.
// This test will start from scratch after encryption, to ensure EVERYTHING has to be re-calculated.
TEST_METHOD(File)
{
// Setup
#if defined _WIN64
const std::string testfile_dir = "../../SimpleTests/";
#elif defined _WIN32
const std::string testfile_dir = "../SimpleTests/";
#endif
const std::string filename_plain = testfile_dir + "testfile.png";
const std::string filename_encrypted = testfile_dir + "testfile.png.crypt";
const std::string filename_decrypted = testfile_dir + "testfile.png.clear.png";
const std::string password = "Der Affe will Zucker";
// Encryption
{
GhettoCryptWrapper::EncryptFile(filename_plain, filename_encrypted, password);
}
// Decryption
{
GhettoCryptWrapper::DecryptFile(filename_encrypted, filename_decrypted, password);
}
// Read in both the base, and the decrypted file
const Flexblock plainfile = ReadFileToBits(filename_plain);
const Flexblock decryptfile = ReadFileToBits(filename_decrypted);
// Assertion (If this fails, maybe check if the image is even readable by an image viewer)
Assert::AreEqual(
PadStringToLength(plainfile, decryptfile.length(), '0', false),
decryptfile
);
}
};
}

View File

@@ -0,0 +1,110 @@
#include "CppUnitTest.h"
#include "../GhettoCrypt/Util.h"
#include "../GhettoCrypt/Config.h"
#include <unordered_map>
#include <codecvt>
#include <sstream>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace GhettoCipher;
// We can generate passwords by just translating a decimal number to base "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
inline std::string Base10_2_X(const unsigned long long int i, const std::string set, unsigned int padding)
{
if (set.length() == 0)
return ""; // Return empty string, if set is empty. Play stupid games, win stupid prizes.
std::stringstream ss;
if (i != 0)
{
{
unsigned long long int buf = i;
while (buf != 0)
{
const unsigned long long int mod = buf % set.length();
buf /= set.length();
ss << set[(std::size_t)mod];
}
}
{
const std::string buf = ss.str();
ss.str("");
for (long long int i = buf.length() - 1; i >= 0; i--)
ss << buf[(std::size_t)i];
}
}
else
{
ss << set[0]; // If i is 0, just pass a null-value. The algorithm would hang otherwise.
}
// Add as much null-values to the left as requested.
if (ss.str().length() < padding)
{
const std::size_t cachedLen = ss.str().length();
const std::string cachedStr = ss.str();
ss.str("");
for (std::size_t i = 0; i < padding - cachedLen; i++)
ss << set[0];
ss << cachedStr;
}
return ss.str();
}
using convert_t = std::codecvt_utf8<wchar_t>;
namespace SimpleTests
{
TEST_CLASS(Password2Key)
{
public:
// Run a few thousand random passwords through the keygen and see if we'll find a collision.
// This test passing does NOT mean that it's resistant! Maybe good, maybe shit! But if it fails, it's definitely shit.
// Already validated range: Password 0 - 1.000.000
TEST_METHOD(CollisionResistance)
{
// To test resistence set this to a high number around a million.
// This will take a LONG while to execute though (about 2.5hrs on my machine), hence why it's set so low.
constexpr std::size_t NUM_RUN_TESTS = 1000;
std::unordered_map<std::bitset<BLOCK_SIZE>, std::string> keys; // <key, password>
// Try NUM_RUN_TESTS passwords
const std::string charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::wstring_convert<convert_t, wchar_t> strconverter;
for (std::size_t i = 0; i < NUM_RUN_TESTS; i++)
{
// Get password
const std::string password = Base10_2_X(i, charset, 0);
// Generate key
const std::bitset<BLOCK_SIZE> newKey = PasswordToKey(password).Get();
// Check if this block is already in our map
if (keys.find(newKey) != keys.cend())
{
std::wstringstream wss;
wss << "Collision found between password \""
<< strconverter.from_bytes(password)
<< "\" and \""
<< strconverter.from_bytes(keys[newKey])
<< "\". The key is \""
<< newKey
<< "\".";
Assert::Fail(wss.str().c_str());
}
// All good? Insert it into our map
keys[newKey] = password;
}
return;
}
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB