From f3b6dc155c48d0557393bae0bda43324eb7fb0f8 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sat, 21 May 2022 20:41:09 +0200 Subject: [PATCH] Implemented digestion (feeding one block at a time) --- GCryptLib/include/GCrypt/Cipher.h | 39 +++++++++------- GCryptLib/include/GCrypt/GCryptWrapper.h | 7 +++ GCryptLib/include/GCrypt/SecureBitset.h | 5 ++- GCryptLib/include/GCrypt/Util.h | 4 +- GCryptLib/src/Cipher.cpp | 57 +++++++++++++++++------- GCryptLib/src/GCryptWrapper.cpp | 47 ++++++++++++++----- 6 files changed, 111 insertions(+), 48 deletions(-) diff --git a/GCryptLib/include/GCrypt/Cipher.h b/GCryptLib/include/GCrypt/Cipher.h index 0685818..e456d75 100644 --- a/GCryptLib/include/GCrypt/Cipher.h +++ b/GCryptLib/include/GCrypt/Cipher.h @@ -3,37 +3,42 @@ #include "GCrypt/Flexblock.h" namespace Leonetienne::GCrypt { - /** Class to apply a block cipher to messages of arbitrary length in a distributed manner + /** Class to apply a block/-stream cipher to messages of arbitrary length in a distributed manner */ class Cipher { public: - explicit Cipher(const Block& key); - explicit Cipher(const std::string& password); + //! Describes the direction the cipher runs in + enum class CIPHER_DIRECTION { + ENCIPHER, + DECIPHER + }; + //! Will initialize this cipher with a key + explicit Cipher(const Block& key, const CIPHER_DIRECTION direction); + + //! Will initialize this cipher with a key + explicit Cipher(const std::string& password, const CIPHER_DIRECTION direction); + + // Disable copying 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; + //! Will digest a data block, and return it + Block Digest(const Block& input); private: Block key; + const CIPHER_DIRECTION direction; + + //! The feistel instance to be used + Feistel feistel; + + //! The last block, required for CBC. + Block lastBlock; //! Will zero the memory used by the key void ZeroKeyMemory(); - - // Initial value for cipher block chaining - Block initializationVector; }; } diff --git a/GCryptLib/include/GCrypt/GCryptWrapper.h b/GCryptLib/include/GCrypt/GCryptWrapper.h index 646e67c..46c5c62 100644 --- a/GCryptLib/include/GCrypt/GCryptWrapper.h +++ b/GCryptLib/include/GCrypt/GCryptWrapper.h @@ -1,5 +1,8 @@ #pragma once #include +#include "GCrypt/Flexblock.h" +#include "GCrypt/Block.h" +#include "GCrypt/Cipher.h" namespace Leonetienne::GCrypt { /** This class is a wrapper to make working with the GhettoCipher @@ -26,6 +29,10 @@ namespace Leonetienne::GCrypt { static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password, bool printProgressReport = false); private: + + //! Will digest a flexblock with a key + static Flexblock DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction); + // No instanciation! >:( GCryptWrapper(); }; diff --git a/GCryptLib/include/GCrypt/SecureBitset.h b/GCryptLib/include/GCrypt/SecureBitset.h index 927d6ab..b4b1a9d 100644 --- a/GCryptLib/include/GCrypt/SecureBitset.h +++ b/GCryptLib/include/GCrypt/SecureBitset.h @@ -2,6 +2,7 @@ #include #include #include +#include namespace Leonetienne::GCrypt { /** Wrapper for std::bitset that zeroes memory upon deletion. @@ -32,7 +33,7 @@ namespace Leonetienne::GCrypt { SecureBitset& operator^=(const SecureBitset& other); SecureBitset operator&(const SecureBitset& other); SecureBitset operator|(const SecureBitset& other); - SecureBitset operator^(const SecureBitset& other); + SecureBitset operator^(const SecureBitset& other) const; SecureBitset operator~() const; SecureBitset& operator<<=(const std::size_t offset); SecureBitset& operator>>=(const std::size_t offset); @@ -174,7 +175,7 @@ namespace Leonetienne::GCrypt { } template - inline SecureBitset SecureBitset::operator^(const SecureBitset& other) { + inline SecureBitset SecureBitset::operator^(const SecureBitset& other) const { SecureBitset bs; bs.bitset = bitset ^ other.bitset; return bs; diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index ced9f56..01019e0 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -241,7 +241,7 @@ namespace Leonetienne::GCrypt { // To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); } return b; @@ -258,7 +258,7 @@ namespace Leonetienne::GCrypt { // To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + b ^= Block(Cipher(fragment, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); } return b; diff --git a/GCryptLib/src/Cipher.cpp b/GCryptLib/src/Cipher.cpp index e3b611a..7fe3125 100644 --- a/GCryptLib/src/Cipher.cpp +++ b/GCryptLib/src/Cipher.cpp @@ -6,18 +6,22 @@ namespace Leonetienne::GCrypt { - Cipher::Cipher(const Block& key) + Cipher::Cipher(const Block& key, const CIPHER_DIRECTION direction) : key { key }, - initializationVector(InitializationVector(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) + Cipher::Cipher(const std::string& password, const CIPHER_DIRECTION direction) : key { PasswordToKey(password) }, - initializationVector(InitializationVector(key)) { + direction { direction }, + lastBlock(InitializationVector(key)), // Initialize our lastBlock with some deterministic initial value, based on the key feistel(key) { + feistel(key) { return; } @@ -28,20 +32,42 @@ namespace Leonetienne::GCrypt { return; } - void Cipher::SetKey(const Block& key) { - ZeroKeyMemory(); + 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; + } + } + - this->key = key; - return; - } - - void Cipher::SetPassword(const std::string& password) { - ZeroKeyMemory(); - - key = PasswordToKey(password); - return; } + /* Flexblock Cipher::Encipher(const Flexblock& data, bool printProgress) const { // Split cleartext into blocks std::vector blocks; @@ -113,6 +139,7 @@ namespace Leonetienne::GCrypt { // Return it return ss.str(); } +*/ // These pragmas only work for MSVC and g++, as far as i know. Beware!!! #if defined _WIN32 || defined _WIN64 diff --git a/GCryptLib/src/GCryptWrapper.cpp b/GCryptLib/src/GCryptWrapper.cpp index 04d7f1f..280a664 100644 --- a/GCryptLib/src/GCryptWrapper.cpp +++ b/GCryptLib/src/GCryptWrapper.cpp @@ -5,15 +5,14 @@ namespace Leonetienne::GCrypt { std::string GCryptWrapper::EncryptString(const std::string& cleartext, const std::string& password) { - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Recode the ascii-string to bits const Flexblock cleartext_bits = StringToBits(cleartext); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); // Recode the ciphertext bits to a hex-string const std::string ciphertext = BitsToHexstring(ciphertext_bits); @@ -23,15 +22,14 @@ namespace Leonetienne::GCrypt { } std::string GCryptWrapper::DecryptString(const std::string& ciphertext, const std::string& password) { - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Recode the hex-string to bits const Flexblock ciphertext_bits = HexstringToBits(ciphertext); // Decrypt the ciphertext bits - const std::string cleartext_bits = cipher.Decipher(ciphertext_bits); + const std::string cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); // Recode the cleartext bits to an ascii-string const std::string cleartext = BitsToString(cleartext_bits); @@ -45,12 +43,11 @@ namespace Leonetienne::GCrypt { // Read the file to bits const Flexblock cleartext_bits = ReadFileToBits(filename_in); - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Encrypt our cleartext bits - const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits, printProgressReport); + const Flexblock ciphertext_bits = DigestFlexblock(cleartext_bits, key, Cipher::CIPHER_DIRECTION::ENCIPHER); // Write our ciphertext bits to file WriteBitsToFile(filename_out, ciphertext_bits); @@ -67,12 +64,11 @@ namespace Leonetienne::GCrypt { // Read the file to bits const Flexblock ciphertext_bits = ReadFileToBits(filename_in); - // Instanciate our cipher and supply a key + // Transform the password to a key const Block key = PasswordToKey(password); - Cipher cipher(key); // Decrypt the ciphertext bits - const Flexblock cleartext_bits = cipher.Decipher(ciphertext_bits, printProgressReport); + const Flexblock cleartext_bits = DigestFlexblock(ciphertext_bits, key, Cipher::CIPHER_DIRECTION::DECIPHER); // Write our cleartext bits to file WriteBitsToFile(filename_out, cleartext_bits); @@ -84,5 +80,32 @@ namespace Leonetienne::GCrypt { } } + Flexblock GCryptWrapper::DigestFlexblock(const Flexblock& data, const Block& key, const Cipher::CIPHER_DIRECTION direction) { + // Split input 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)) + ); + } + + // Create cipher instance + Cipher cipher(key, direction); + + // Digest all blocks + for (Block& block : blocks) { + block = cipher.Digest(block); + } + + // Concatenate ciphertext blocks back into a flexblock + std::stringstream ss; + for (Block& b : blocks) { + ss << b; + } + + // Return it + return ss.str(); + } }