diff --git a/INCLUDE/GhettoCrypt.cpp b/INCLUDE/GhettoCrypt.cpp new file mode 100644 index 0000000..731b8c2 --- /dev/null +++ b/INCLUDE/GhettoCrypt.cpp @@ -0,0 +1,453 @@ +/* +* BSD 2-Clause License +* +* Copyright (c) 2021, Leon Etienne +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "GhettoCrypt.h" + +/*** ./../GhettoCrypt/Cipher.cpp ***/ + +#include + +GhettoCipher::Cipher::Cipher(const Block& key) + : + key { key } +{ + + return; +} + +GhettoCipher::Cipher::Cipher(const std::string& password) +{ + key = PasswordToKey(password); + + return; +} + +GhettoCipher::Cipher::~Cipher() +{ + // Clear key memory + ZeroKeyMemory(); + + return; +} + +void GhettoCipher::Cipher::SetKey(const Block& key) +{ + ZeroKeyMemory(); + + this->key = key; + return; +} + +void GhettoCipher::Cipher::SetPassword(const std::string& password) +{ + ZeroKeyMemory(); + + key = PasswordToKey(password); + return; +} + +GhettoCipher::Flexblock GhettoCipher::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] : emptyBlock; + blocks[i] = feistel.Encipher(blocks[i] ^ lastBlock); + } + + // Concatenate ciphertext blocks back into a flexblock + std::stringstream ss; + for (Block& b : blocks) + ss << b; + + // Return it + return ss.str(); +} + +GhettoCipher::Flexblock GhettoCipher::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 = emptyBlock; + + 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; + + 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(); +} + +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#endif +void GhettoCipher::Cipher::ZeroKeyMemory() +{ + key.reset(); + return; +} +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#endif + +const GhettoCipher::Block GhettoCipher::Cipher::emptyBlock; + + +/*** ./../GhettoCrypt/Feistel.cpp ***/ + + +GhettoCipher::Feistel::Feistel(const Block& key) +{ + SetKey(key); + return; +} + +GhettoCipher::Feistel::~Feistel() +{ + ZeroKeyMemory(); + + return; +} + +void GhettoCipher::Feistel::SetKey(const Block& key) +{ + GenerateRoundKeys(key); + return; +} + +GhettoCipher::Block GhettoCipher::Feistel::Encipher(const Block& data) const +{ + return Run(data, false); +} + +GhettoCipher::Block GhettoCipher::Feistel::Decipher(const Block& data) const +{ + return Run(data, true); +} + +GhettoCipher::Block GhettoCipher::Feistel::Run(const Block& data, bool reverseKeys) const +{ + const auto splitData = FeistelSplit(data); + GhettoCipher::Halfblock l = splitData.first; + GhettoCipher::Halfblock r = splitData.second; + + Halfblock tmp; + + for (std::size_t i = 0; i < N_ROUNDS; i++) + { + // Calculate key index + std::size_t keyIndex; + if (reverseKeys) + keyIndex = N_ROUNDS - i - 1; + else + keyIndex = i; + + // Do a feistel round + tmp = r; + r = l ^ F(r, roundKeys[keyIndex]); + l = tmp; + } + + return FeistelCombine(r, l); +} + +GhettoCipher::Halfblock GhettoCipher::Feistel::F(Halfblock m, const Block& key) +{ + // Made-up F function + + // Expand to full bitwidth + Block m_expanded = ExpansionFunction(m); + + // Shift to left by 1 + m_expanded = Shiftl(m_expanded, 1); + + // Xor with key + m_expanded ^= key; + + // Non-linearly apply subsitution boxes + std::stringstream ss; + const std::string m_str = m_expanded.to_string(); + + for (std::size_t i = 0; i < m_str.size(); i += 4) + { + ss << SBox(m_str.substr(i, 4)); + } + + m_expanded = Block(ss.str()); + + // Return the compressed version + return CompressionFunction(m_expanded); +} + +std::pair GhettoCipher::Feistel::FeistelSplit(const Block& block) +{ + const std::string bits = block.to_string(); + + Halfblock l(bits.substr(0, bits.size() / 2)); + Halfblock r(bits.substr(bits.size() / 2)); + + return std::make_pair(l, r); +} + +GhettoCipher::Block GhettoCipher::Feistel::FeistelCombine(const Halfblock& l, const Halfblock& r) +{ + return Block(l.to_string() + r.to_string()); +} + +GhettoCipher::Block GhettoCipher::Feistel::ExpansionFunction(const Halfblock& block) +{ + std::stringstream ss; + const std::string bits = block.to_string(); + + // We have to double the bits! + for (std::size_t i = 0; i < bits.size(); i += 2) + { + const std::string sub = bits.substr(i, 2); + + if (sub == "00") ss << "1101"; + else if (sub == "01") ss << "1000"; + else if (sub == "10") ss << "0010"; + else if (sub == "11") ss << "0111"; + + } + + return Block(ss.str()); +} + +GhettoCipher::Halfblock GhettoCipher::Feistel::CompressionFunction(const Block& block) +{ + std::stringstream ss; + const std::string bits = block.to_string(); + + // We have to double the bits! + for (std::size_t i = 0; i < bits.size(); i += 4) + { + const std::string sub = bits.substr(i, 4); + + if (sub == "0000") ss << "10"; + else if (sub == "0001") ss << "01"; + else if (sub == "0010") ss << "10"; + else if (sub == "0011") ss << "10"; + else if (sub == "0100") ss << "11"; + else if (sub == "0101") ss << "01"; + else if (sub == "0110") ss << "00"; + else if (sub == "0111") ss << "11"; + else if (sub == "1000") ss << "01"; + else if (sub == "1001") ss << "00"; + else if (sub == "1010") ss << "11"; + else if (sub == "1011") ss << "00"; + else if (sub == "1100") ss << "11"; + else if (sub == "1101") ss << "10"; + else if (sub == "1110") ss << "00"; + else if (sub == "1111") ss << "01"; + } + + return Halfblock(ss.str()); +} + +std::string GhettoCipher::Feistel::SBox(const std::string& in) +{ + if (in == "0000") return "1100"; + else if (in == "0001") return "1000"; + else if (in == "0010") return "0001"; + else if (in == "0011") return "0111"; + else if (in == "0100") return "1011"; + else if (in == "0101") return "0011"; + else if (in == "0110") return "1101"; + else if (in == "0111") return "1111"; + else if (in == "1000") return "0000"; + else if (in == "1001") return "1010"; + else if (in == "1010") return "0100"; + else if (in == "1011") return "1001"; + else if (in == "1100") return "0010"; + else if (in == "1101") return "1110"; + else if (in == "1110") return "0101"; + else /*if (in == "1111")*/ return "0110"; +} + +void GhettoCipher::Feistel::GenerateRoundKeys(const Block& seedKey) +{ + // Generate round keys via output feedback modus (OFM) method + + // Clear initial key memory + ZeroKeyMemory(); + roundKeys = Keyset(); + + // Generate new keys from the seed key + roundKeys[0] = seedKey; + roundKeys[1] = (Shiftl(seedKey, 32) ^ roundKeys[0]); + + for (std::size_t i = 2; i < roundKeys.size(); i++) + { + roundKeys[i] = Shiftl(roundKeys[i - 1], i + 32) ^ roundKeys[i - 2]; + } + + return; +} + +// These pragmas only work for MSVC, as far as i know. Beware!!! +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", off ) +#endif +void GhettoCipher::Feistel::ZeroKeyMemory() +{ + for (Block& key : roundKeys) + key.reset(); + + return; +} +#if defined _WIN32 || defined _WIN64 +#pragma optimize("", on ) +#endif + + +/*** ./../GhettoCrypt/GhettoCryptWrapper.cpp ***/ + + +std::string GhettoCipher::GhettoCryptWrapper::EncryptString(const std::string& cleartext, const std::string& password) +{ + // Instanciate our cipher and supply a key + Cipher cipher(password); + + // Recode the ascii-string to bits + const Flexblock cleartext_bits = StringToBits(cleartext); + + // Encrypt our cleartext bits + const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + + // Recode the ciphertext bits to a hex-string + const std::string ciphertext = BitsToHexstring(ciphertext_bits); + + // Return it + return ciphertext; +} + +std::string GhettoCipher::GhettoCryptWrapper::DecryptString(const std::string& ciphertext, const std::string& password) +{ + // Instanciate our cipher and supply a key + Cipher cipher(password); + + // 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); + + // Recode the cleartext bits to an ascii-string + const std::string cleartext = BitsToString(cleartext_bits); + + // Return it + return cleartext; +} + +bool GhettoCipher::GhettoCryptWrapper::EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password) +{ + try + { + // Read the file to bits + const Flexblock cleartext_bits = ReadFileToBits(filename_in); + + // Instanciate our cipher and supply a key + Cipher cipher(password); + + // Encrypt our cleartext bits + const Flexblock ciphertext_bits = cipher.Encipher(cleartext_bits); + + // Write our ciphertext bits to file + WriteBitsToFile(filename_out, ciphertext_bits); + + return true; + } + catch (std::runtime_error&) + { + return false; + } +} + +bool GhettoCipher::GhettoCryptWrapper::DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password) +{ + try + { + // Read the file to bits + const Flexblock ciphertext_bits = ReadFileToBits(filename_in); + + // Instanciate our cipher and supply a key + Cipher cipher(password); + + // Decrypt the ciphertext bits + const Flexblock cleartext_bits = cipher.Decipher(ciphertext_bits); + + // Write our cleartext bits to file + WriteBitsToFile(filename_out, cleartext_bits); + + return true; + } + catch (std::runtime_error&) + { + return false; + } +} + diff --git a/INCLUDE/GhettoCrypt.h b/INCLUDE/GhettoCrypt.h new file mode 100644 index 0000000..6648ea8 --- /dev/null +++ b/INCLUDE/GhettoCrypt.h @@ -0,0 +1,475 @@ +/* +* BSD 2-Clause License +* +* Copyright (c) 2021, Leon Etienne +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +/*** ./../GhettoCrypt/GhettoCryptWrapper.h ***/ + +#pragma once +#include + +namespace GhettoCipher +{ + /** This class is a wrapper to make working with the GhettoCipher super easy with a python-like syntax + */ + class GhettoCryptWrapper + { + public: + //! Will encrypt a string and return it hexadecimally encoded. + static std::string EncryptString(const std::string& cleartext, const std::string& password); + + //! Will decrypt a hexadecimally encoded string. + static std::string DecryptString(const std::string& ciphertext, const std::string& password); + + //! Will encrypt a file. + //! Returns false if anything goes wrong (like, file-access). + //! @filename_in The file to be read. + //! @filename_out The file the encrypted version should be saved in. + static bool EncryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password); + + //! Will decrypt a file. + //! Returns false if anything goes wrong (like, file-access). + //! @filename_in The file to be read. + //! @filename_out The file the decrypted version should be saved in. + static bool DecryptFile(const std::string& filename_in, const std::string& filename_out, const std::string& password); + + private: + // No instanciation! >:( + GhettoCryptWrapper(); + }; +} + +/*** ./../GhettoCrypt/Flexblock.h ***/ + +#pragma once +#include + +namespace GhettoCipher +{ + //! A "bitset" of variable length + typedef std::string Flexblock; +} + +/*** ./../GhettoCrypt/Config.h ***/ + +#pragma once + +namespace GhettoCipher +{ + constexpr int BLOCK_SIZE = 128; + constexpr int N_ROUNDS = 64; +} + +/*** ./../GhettoCrypt/Halfblock.h ***/ + +#pragma once +#include + +namespace GhettoCipher +{ + constexpr int HALFBLOCK_SIZE = (BLOCK_SIZE / 2); + typedef std::bitset Halfblock; +} + +/*** ./../GhettoCrypt/Block.h ***/ + +#pragma once +#include + +namespace GhettoCipher +{ + typedef std::bitset Block; +} + +/*** ./../GhettoCrypt/Util.h ***/ + +#pragma once +#include +#include +#include + +namespace GhettoCipher +{ + //! Mod-operator that works with negative values + inline int Mod(int numerator, int denominator) + { + return (denominator + (numerator % denominator)) % denominator; + } + + //! Will perform a wrapping left-bitshift on a bitset + template + inline std::bitset Shiftl(const std::bitset& bits, std::size_t amount) + { + std::stringstream ss; + const std::string bitss = bits.to_string(); + + for (std::size_t i = 0; i < bitss.size(); i++) + ss << bitss[Mod((i + amount), bitss.size())]; + + return std::bitset(ss.str()); + } + + //! Will perform a wrapping right-bitshift on a bitset + template + inline std::bitset Shiftr(const std::bitset& bits, std::size_t amount) + { + std::stringstream ss; + const std::string bitss = bits.to_string(); + + for (std::size_t i = 0; i < bitss.size(); i++) + ss << bitss[Mod((i - amount), bitss.size())]; + + return std::bitset(ss.str()); + } + + inline std::string PadStringToLength(const std::string& str, const std::size_t len, const char pad, const bool padLeft = true) + { + // Fast-reject: Already above padded length + if (str.length() >= len) + return str; + + std::stringstream ss; + + // Pad left: + if (padLeft) + { + for (std::size_t i = 0; i < len - str.size(); i++) + ss << pad; + ss << str; + } + // Pad right: + else + { + ss << str; + for (std::size_t i = 0; i < len - str.size(); i++) + ss << pad; + } + + return ss.str(); + } + + //! Will convert a string to a fixed data block + inline Block StringToBitblock(const std::string& s) + { + std::stringstream ss; + + for (std::size_t i = 0; i < s.size(); i++) + ss << std::bitset<8>(s[i]); + + // Pad rest with zeores + return Block(PadStringToLength(ss.str(), 128, '0', false)); + } + + //! Will convert a string to a flexible data block + inline Flexblock StringToBits(const std::string& s) + { + std::stringstream ss; + + for (std::size_t i = 0; i < s.size(); i++) + ss << std::bitset<8>(s[i]); + + return Flexblock(ss.str()); + } + + //! Will convert a fixed data block to a string + inline std::string BitblockToString(const Block& bits) + { + std::stringstream ss; + + const std::string bitstring = bits.to_string(); + + for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) + { + ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); + } + + return ss.str(); + } + + //! Will convert a flexible data block to a string + inline std::string BitsToString(const Flexblock& bits) + { + std::stringstream ss; + + const std::string bitstring = bits; + + for (std::size_t i = 0; i < bits.size(); i += 8) + { + ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); + } + + return ss.str(); + } + + //! Turns a fixed data block into a hex-string + inline std::string BitblockToHexstring(const Block& b) + { + std::stringstream ss; + const std::string charset = "0123456789abcdef"; + const std::string bstr = b.to_string(); + + for (std::size_t i = 0; i < bstr.size(); i += 4) + ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; + + return ss.str(); + } + + //! Turns a flexible data block into a hex-string + inline std::string BitsToHexstring(const Flexblock& b) + { + std::stringstream ss; + const std::string charset = "0123456789abcdef"; + const std::string bstr = b; + + for (std::size_t i = 0; i < bstr.size(); i += 4) + ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; + + return ss.str(); + } + + + //! Turns a hex string into a fixed data block + inline Block HexstringToBitblock(const std::string& hexstring) + { + std::stringstream ss; + + for (std::size_t i = 0; i < hexstring.size(); i++) + { + const char c = hexstring[i]; + + // Get value + std::size_t value; + if ((c >= '0') && (c <= '9')) + // Is it a number? + value = (c - '0') + 0; + else if ((c >= 'a') && (c <= 'f')) + // Else, it is a lowercase letter + value = (c - 'a') + 10; + else + throw std::logic_error("non-hex string detected in HexstringToBits()"); + + // Append to our bits + ss << std::bitset<4>(value); + } + + return Block(ss.str()); + } + + //! Turns a hex string into a flexible data block + inline Flexblock HexstringToBits(const std::string& hexstring) + { + std::stringstream ss; + + for (std::size_t i = 0; i < hexstring.size(); i++) + { + const char c = hexstring[i]; + + // Get value + std::size_t value; + if ((c >= '0') && (c <= '9')) + // Is it a number? + value = (c - '0') + 0; + else if ((c >= 'a') && (c <= 'f')) + // Else, it is a lowercase letter + value = (c - 'a') + 10; + else + throw std::logic_error("non-hex string detected in HexstringToBits()"); + + // Append to our bits + ss << std::bitset<4>(value); + } + + return ss.str(); + } + + //! Creates a key of size key-size from a password of arbitrary length. + inline Block PasswordToKey(const std::string& in) + { + Block b; + + // Segment the password in segments of key-size, and xor them together. + for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE / 8) + b ^= StringToBitblock(in.substr(i, BLOCK_SIZE / 8)); + + return b; + } + + //! Will read a file into a flexblock + inline Flexblock ReadFileToBits(const std::string& filepath) + { + // Read file + std::ifstream ifs(filepath, std::ios::binary); + + if (!ifs.good()) + throw std::runtime_error("Unable to open ifilestream!"); + + std::stringstream ss; + std::copy( + std::istreambuf_iterator(ifs), + std::istreambuf_iterator(), + std::ostreambuf_iterator(ss) + ); + + ifs.close(); + + const std::string bytes = ss.str(); + + // Convert bytes to bits + return StringToBits(bytes); + } + + //! Will save bits to a binary file + inline void WriteBitsToFile(const std::string& filepath, const Flexblock& bits) + { + // Convert bits to bytes + const std::string bytes = BitsToString(bits); + + // Write bits to file + std::ofstream ofs(filepath, std::ios::binary); + + if (!ofs.good()) + throw std::runtime_error("Unable to open ofilestream!"); + + ofs.write(bytes.data(), bytes.length()); + ofs.close(); + + return; + } +} + +/*** ./../GhettoCrypt/Keyset.h ***/ + +#pragma once +#include + +namespace GhettoCipher +{ + typedef std::array Keyset; +} + +/*** ./../GhettoCrypt/Feistel.h ***/ + +#pragma once + +namespace GhettoCipher +{ + /** Class to perform a feistel block chipher + */ + class Feistel + { + public: + explicit Feistel(const Block& key); + + Feistel(const Feistel& other) = delete; + Feistel(Feistel&& other) noexcept = delete; + + ~Feistel(); + + //! Will set the seed-key for this feistel network. + //! Roundkeys will be derived from this. + void SetKey(const Block& key); + + //! Will encipher a data block via the set seed-key + Block Encipher(const Block& data) const; + + //! Will decipher a data block via the set seed-key + Block Decipher(const Block& data) const; + + private: + //! Will run the feistel rounds, with either regular key order or reversed key order + Block Run(const Block& data, bool reverseKeys) const; + + //! Arbitrary cipher function + static Halfblock F(Halfblock m, const Block& key); + + //! Split a data block into two half blocks (into L and R) + static std::pair FeistelSplit(const Block& block); + + //! Combine two half blocks (L and R) into a regular data block + static Block FeistelCombine(const Halfblock& l, const Halfblock& r); + + //! Will expand a halfblock to a fullblock + static Block ExpansionFunction(const Halfblock& block); + + //! Will compress a fullblock to a halfblock + static Halfblock CompressionFunction(const Block& block); + + //! Substitutes four bits by static random others + static std::string SBox(const std::string& in); + + //! Will generate a the round keys + void GenerateRoundKeys(const Block& seedKey); + + //! Will zero the memory used by the keyset + void ZeroKeyMemory(); + + Keyset roundKeys; + }; +} + +/*** ./../GhettoCrypt/Cipher.h ***/ + +#pragma once + +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 + static const Block emptyBlock; + }; +}