diff --git a/GCryptLib/include/GCrypt/Cipher.h b/GCryptLib/include/GCrypt/GCipher.h similarity index 68% rename from GCryptLib/include/GCrypt/Cipher.h rename to GCryptLib/include/GCrypt/GCipher.h index e456d75..c4d7120 100644 --- a/GCryptLib/include/GCrypt/Cipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -5,32 +5,32 @@ namespace Leonetienne::GCrypt { /** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner */ - class Cipher { + class GCipher { public: //! Describes the direction the cipher runs in - enum class CIPHER_DIRECTION { + enum class DIRECTION { ENCIPHER, DECIPHER }; //! Will initialize this cipher with a key - explicit Cipher(const Block& key, const CIPHER_DIRECTION direction); + explicit GCipher(const Block& key, const DIRECTION direction); //! Will initialize this cipher with a key - explicit Cipher(const std::string& password, const CIPHER_DIRECTION direction); + explicit GCipher(const std::string& password, const DIRECTION direction); // Disable copying - Cipher(const Cipher& other) = delete; - Cipher(Cipher&& other) noexcept = delete; + GCipher(const GCipher& other) = delete; + GCipher(GCipher&& other) noexcept = delete; - ~Cipher(); + ~GCipher(); //! Will digest a data block, and return it Block Digest(const Block& input); private: Block key; - const CIPHER_DIRECTION direction; + const DIRECTION direction; //! The feistel instance to be used Feistel feistel; diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GCryptWrapper.h index 46c5c62..664323e 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GCryptWrapper.h @@ -2,7 +2,7 @@ #include #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -31,7 +31,7 @@ namespace Leonetienne::GCrypt { private: //! Will digest a flexblock with a key - static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction); + static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction); // No instanciation! >:( GCryptWrapper(); diff --git a/GCryptLib/include/GCrypt/Hasher.h b/GCryptLib/include/GCrypt/Hasher.h index 55e8483..a576137 100644 --- a/GCryptLib/include/GCrypt/Hasher.h +++ b/GCryptLib/include/GCrypt/Hasher.h @@ -3,7 +3,7 @@ #include "GCrypt/Flexblock.h" #include "GCrypt/Block.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" namespace Leonetienne::GCrypt { /** This class implements a hash function, based on the GCrypt cipher @@ -12,8 +12,11 @@ namespace Leonetienne::GCrypt { public: Hasher(); - //! Will add the hash value of `data` to the hashsum - void Digest(const Block& data); + //! Will add the hash value of the block `data` to the hashsum. + //! WARNING: If you compute hashes using this digestive method, + //! you REALLY REALLY should add a trailing block just containing the cleartext size! + //! You MOST LIKELY just want to use the wrapper function GHash::CalculateHashsum(Flexblock const&) instead! + void DigestBlock(const Block& data); //! Will return the current hashsum const Block& GetHashsum() const; @@ -23,7 +26,7 @@ namespace Leonetienne::GCrypt { private: //! The cipher to use - Cipher cipher; + GCipher cipher; //! The current state of the hashsum Block block; diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 789f540..fc25dcc 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -9,7 +9,7 @@ #include "GCrypt/Block.h" #include "GCrypt/Flexblock.h" #include "GCrypt/Config.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" #include "GCrypt/InitializationVector.h" namespace Leonetienne::GCrypt { diff --git a/GCryptLib/src/Cipher.cpp b/GCryptLib/src/Cipher.cpp deleted file mode 100644 index 4497e7e..0000000 --- a/GCryptLib/src/Cipher.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include -#include -#include -#include "GCrypt/Cipher.h" -#include "GCrypt/Util.h" -#include "GCrypt/InitializationVector.h" - -namespace Leonetienne::GCrypt { - - Cipher::Cipher(const Block& key, const CIPHER_DIRECTION direction) - : - key { key }, - direction { direction }, - lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key - feistel(key) { - - return; - } - - Cipher::Cipher(const std::string& password, const CIPHER_DIRECTION direction) - : - key { PasswordToKey(password) }, - direction { direction }, - lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { - feistel(key) { - return; - } - - Cipher::~Cipher() { - // Clear key memory - ZeroKeyMemory(); - - return; - } - - Block Cipher::Digest(const Block& input) { - - switch (direction) { - case CIPHER_DIRECTION::ENCIPHER: { - // Rename our input to cleartext - const Block& cleartext = input; - - // First, xor our cleartext with the last block, and then encipher it - Block ciphertext = feistel.Encipher(cleartext ^ lastBlock); - - // Now set our lastBlock to the ciphertext of this block - lastBlock = ciphertext; - - // Now return the ciphertext - return ciphertext; - } - - case CIPHER_DIRECTION::DECIPHER: { - // Rename our input into ciphertext - const Block& ciphertext = input; - - // First, decipher our ciphertext, and then xor it with our last block - Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock; - - // Now set our lastBLock to the ciphertext of this block - lastBlock = ciphertext; - - // Now return the cleartext - return cleartext; - } - } - - throw std::runtime_error("Unreachable branch reached."); - } - - /* - Flexblock Cipher::Encipher(const Flexblock& data, bool printProgress) const { - // Split cleartext into blocks - std::vector blocks; - - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) - ); - } - - // Encrypt individual blocks using cipher block chaining - Feistel feistel(key); - - for (std::size_t i = 0; i < blocks.size(); i++) { - // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block. - if ((i % ((blocks.size() > 1000)? 100 : 10) == 0) && (printProgress)) { - std::cout << "Encrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100 / blocks.size()) << "%)" << std::endl; - } - - const Block& lastBlock = (i>0) ? blocks[i-1] : initializationVector; - blocks[i] = feistel.Encipher(blocks[i] ^ lastBlock); // Xor last cipher block with new clear text block before E() - } - - // Concatenate ciphertext blocks back into a flexblock - std::stringstream ss; - for (Block& b : blocks) { - ss << b; - } - - // Return it - return ss.str(); - } - - Flexblock Cipher::Decipher(const Flexblock& data, bool printProgress) const { - // Split ciphertext into blocks - std::vector blocks; - - for (std::size_t i = 0; i < data.size(); i += BLOCK_SIZE) { - blocks.push_back(Block( - PadStringToLength(data.substr(i, BLOCK_SIZE), BLOCK_SIZE, '0', false)) - ); - } - - // Decrypt individual blocks - Feistel feistel(key); - - // We can't do this in-loop for decryption, because we are decrypting the blocks in-place. - Block lastBlock = initializationVector; - - for (std::size_t i = 0; i < blocks.size(); i++) { - // Print reports if desired. If we have > 1000 blocks, print one report every 100 blocks. Otherwise for every 10th block. - if ((i % ((blocks.size() > 1000) ? 100 : 10) == 0) && (printProgress)) { - std::cout << "Decrypting... (Block " << i << " / " << blocks.size() << " - " << ((float)i*100/ blocks.size()) << "%)" << std::endl; - } - - Block tmpCopy = blocks[i]; - - blocks[i] = feistel.Decipher(blocks[i]) ^ lastBlock; // Decipher cipher block [i] and then xor it with the last cipher block [i-1] we've had - - lastBlock = std::move(tmpCopy); - } - - // Concatenate ciphertext blocks back into a flexblock - std::stringstream ss; - for (Block& b : blocks) { - ss << b; - } - - // Return it - return ss.str(); - } -*/ - - // These pragmas only work for MSVC and g++, as far as i know. Beware!!! -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", off ) -#elif defined __GNUG__ -#pragma GCC push_options -#pragma GCC optimize ("O0") -#endif - void Cipher::ZeroKeyMemory() { - key.reset(); - return; - } -#if defined _WIN32 || defined _WIN64 -#pragma optimize("", on ) -#elif defined __GNUG__ -#pragma GCC pop_options -#endif - -} - diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp new file mode 100644 index 0000000..8e30c93 --- /dev/null +++ b/GCryptLib/src/GCipher.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include "GCrypt/GCipher.h" +#include "GCrypt/Util.h" +#include "GCrypt/InitializationVector.h" + +namespace Leonetienne::GCrypt { + + GCipher::GCipher(const Block& key, const DIRECTION direction) + : + key { key }, + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key + feistel(key) { + + return; + } + + GCipher::GCipher(const std::string& password, const DIRECTION direction) + : + key { PasswordToKey(password) }, + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { + feistel(key) { + return; + } + + GCipher::~GCipher() { + // Clear key memory + ZeroKeyMemory(); + + return; + } + + Block GCipher::Digest(const Block& input) { + + switch (direction) { + case DIRECTION::ENCIPHER: { + // Rename our input to cleartext + const Block& cleartext = input; + + // First, xor our cleartext with the last block, and then encipher it + Block ciphertext = feistel.Encipher(cleartext ^ lastBlock); + + // Now set our lastBlock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the ciphertext + return ciphertext; + } + + case DIRECTION::DECIPHER: { + // Rename our input into ciphertext + const Block& ciphertext = input; + + // First, decipher our ciphertext, and then xor it with our last block + Block cleartext = feistel.Decipher(ciphertext) ^ lastBlock; + + // Now set our lastBLock to the ciphertext of this block + lastBlock = ciphertext; + + // Now return the cleartext + return cleartext; + } + } + + throw std::runtime_error("Unreachable branch reached."); + } + + // These pragmas only work for MSVC and g++, as far as i know. Beware!!! +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#elif defined __GNUG__ +#pragma GCC push_options +#pragma GCC optimize ("O0") +#endif + void GCipher::ZeroKeyMemory() { + key.reset(); + return; + } +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#elif defined __GNUG__ +#pragma GCC pop_options +#endif + +} + diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GCryptWrapper.cpp index 280a664..1ae321b 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GCryptWrapper.cpp @@ -1,5 +1,5 @@ #include "GCrypt/GCryptWrapper.h" -#include "GCrypt/Cipher.h" +#include "GCrypt/GCipher.h" #include "GCrypt/Util.h" namespace Leonetienne::GCrypt { @@ -12,7 +12,7 @@ namespace Leonetienne::GCrypt { const Flexblock cleartext_bits = StringToBits(cleartext); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Recode the ciphertext bits to a hex-string const std::string ciphertext = BitsToHexstring(ciphertext_bits); @@ -29,7 +29,7 @@ namespace Leonetienne::GCrypt { const Flexblock ciphertext_bits = HexstringToBits(ciphertext); // Decrypt the ciphertext bits - const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); + const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Recode the cleartext bits to an ascii-string const std::string cleartext = BitsToString(cleartext_bits); @@ -47,7 +47,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, GCipher::DIRECTION::ENCIPHER); // Write our ciphertext bits to file WriteBitsToFile(filename_out, ciphertext_bits); @@ -68,7 +68,7 @@ namespace Leonetienne::GCrypt { const Block key = PasswordToKey(password); // Decrypt the ciphertext bits - const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); + const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, GCipher::DIRECTION::DECIPHER); // Write our cleartext bits to file WriteBitsToFile(filename_out, cleartext_bits); @@ -80,7 +80,7 @@ namespace Leonetienne::GCrypt { } } - Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction) { + Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const GCipher::DIRECTION direction) { // Split input into blocks std::vector blocks; @@ -91,9 +91,8 @@ namespace Leonetienne::GCrypt { } // Create cipher instance - Cipher cipher(key, direction); + GCipher cipher(key, direction); - // Digest all blocks for (Block& block : blocks) { block = cipher.Digest(block); } diff --git a/GCryptLib/src/Hasher.cpp b/GCryptLib/src/Hasher.cpp index 7767bdd..9e117ea 100644 --- a/GCryptLib/src/Hasher.cpp +++ b/GCryptLib/src/Hasher.cpp @@ -8,14 +8,14 @@ namespace Leonetienne::GCrypt { // Initialize our cipher with a static, but randomly distributed key. cipher( StringToBitblock("CfRtNdMTP4Y5CWRd"), - Cipher::CIPHER_DIRECTION::ENCIPHER + GCipher::DIRECTION::ENCIPHER ) { block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); return; } - - void Hasher::Digest(const Block& data) { + + void Hasher::DigestBlock(const Block& data) { // Encipher the current block, and xor it on the current hashsum block ^= cipher.Digest(data); return; @@ -46,7 +46,7 @@ namespace Leonetienne::GCrypt { // Digest all blocks for (Block& block : blocks) { - hasher.Digest(block); + hasher.DigestBlock(block); } // Return the total hashsum diff --git a/GCryptLib/test/EncryptEqualsDecrypt.cpp b/GCryptLib/test/EncryptEqualsDecrypt.cpp index 4f7d965..5d735bc 100644 --- a/GCryptLib/test/EncryptEqualsDecrypt.cpp +++ b/GCryptLib/test/EncryptEqualsDecrypt.cpp @@ -11,7 +11,7 @@ TEST_CASE(__FILE__"/SingleBlock_NoPadding", "[Encryption/Decryption consistency] // Instanciate our cipher and supply a key const Block key = PasswordToKey("1234"); - const Cipher cipher(key); + const Cipher cipher(key, Cipher::CIPHER_DIRECTION::Encryption); // Recode the ascii-string to bits const Flexblock cleartext_bits =