From 5afd772a846ce2b1acfe760bb2a4cc94e2c594ac Mon Sep 17 00:00:00 2001 From: Leon Etienne Date: Fri, 13 May 2022 11:37:08 +0200 Subject: [PATCH] Update documentation for PasswordToKey function --- GhettoCrypt/Util.h | 639 ++++++++++++++++++++++----------------------- 1 file changed, 319 insertions(+), 320 deletions(-) diff --git a/GhettoCrypt/Util.h b/GhettoCrypt/Util.h index e8458f8..4150438 100644 --- a/GhettoCrypt/Util.h +++ b/GhettoCrypt/Util.h @@ -1,320 +1,319 @@ -#pragma once -#include -#include -#include -#include -#include "SecureBitset.h" -#include "Block.h" -#include "Flexblock.h" -#include "Config.h" -#include "Cipher.h" -#include "InitializationVector.h" - -namespace GhettoCipher -{ - //! Mod-operator that works with negative values - inline int Mod(const int numerator, const int denominator) - { - return (denominator + (numerator % denominator)) % denominator; - } - - //! Will perform a wrapping left-bitshift on a bitset - template - inline SecureBitset Shiftl(const SecureBitset& bits, const 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((int)(i + amount), (int)bitss.size())]; - - return SecureBitset(ss.str()); - } - - //! Will perform a wrapping right-bitshift on a bitset - template - inline SecureBitset Shiftr(const SecureBitset& bits, const 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 SecureBitset(ss.str()); - } - - //! Will pad a string to a set length with a certain character - 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-size 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-size data block to a bytestring - inline std::string BitblockToBytes(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 fixed-size data block to a string - //! The difference to BitblockToBytes() is, that it strips excess nullbytes - inline std::string BitblockToString(const Block& bits) - { - // Decode to bytes - std::string text = BitblockToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } - - //! Will convert a flexible data block to a bytestring - inline std::string BitsToBytes(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(); - } - - //! Will convert a flexible data block to a string - //! //! The difference to BitsToBytes() is, that it strips excess nullbytes - inline std::string BitsToString(const Flexblock& bits) - { - // Decode to bytes - std::string text = BitsToBytes(bits); - - // Dümp excess nullbytes - text.resize(strlen(text.data())); - - return text; - } - - //! Turns a fixed-size 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-size 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 = ((std::size_t)c - '0') + 0; - else if ((c >= 'a') && (c <= 'f')) - // Else, it is a lowercase letter - value = ((std::size_t)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 = ((std::size_t)c - '0') + 0; - else if ((c >= 'a') && (c <= 'f')) - // Else, it is a lowercase letter - value = ((std::size_t)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 BLOCK_SIZE from a password of arbitrary length. - //! Using passwords larger (in bits) than BLOCK_SIZE is generally not recommended. - //! Note that if your password is shorter (in bits) than BLOCK_SIZE, the rest of the key will be padded with 0 (see next line!). - //! To provide a better initial key, (and to get rid of padding zeroes), the raw result (b) will be xor'd with an initialization vector based on b. - //! : return b ^ iv(b) - inline Block PasswordToKey(const std::string& in) - { - // Let's provide a nice initial value to be sure even a password of length 0 results in a proper key - Block b = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); - - // 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) - { - const Block fragment = StringToBitblock( - PadStringToLength(in.substr(i, BLOCK_SIZE / 8), BLOCK_SIZE / 8, 0, false) - ); - - // To provide confusion, xor the blocks together - // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); - } - - - return b; - } - - //! Will reduce a flexblock (they are of arbitrary length) to a single block. - //! This single block should change completely, if a single bit in the input flexblock changes anywhere. - inline Block ReductionFunction_Flexblock2Block(const Flexblock& in) - { - Block b; // No initialization vector needed here - - // Segment the input in segments of BLOCK_SIZE, and xor them together. - for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE) - { - const Block fragment = Block(PadStringToLength(in.substr(i, BLOCK_SIZE), BLOCK_SIZE, 0, false)); - - // To provide confusion, xor the blocks together - // To provide diffusion, hash fragment to fragment' first - b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); - } - - 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 = BitsToBytes(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; - } -} +#pragma once +#include +#include +#include +#include +#include "SecureBitset.h" +#include "Block.h" +#include "Flexblock.h" +#include "Config.h" +#include "Cipher.h" +#include "InitializationVector.h" + +namespace GhettoCipher +{ + //! Mod-operator that works with negative values + inline int Mod(const int numerator, const int denominator) + { + return (denominator + (numerator % denominator)) % denominator; + } + + //! Will perform a wrapping left-bitshift on a bitset + template + inline SecureBitset Shiftl(const SecureBitset& bits, const 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((int)(i + amount), (int)bitss.size())]; + + return SecureBitset(ss.str()); + } + + //! Will perform a wrapping right-bitshift on a bitset + template + inline SecureBitset Shiftr(const SecureBitset& bits, const 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 SecureBitset(ss.str()); + } + + //! Will pad a string to a set length with a certain character + 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-size 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-size data block to a bytestring + inline std::string BitblockToBytes(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 fixed-size data block to a string + //! The difference to BitblockToBytes() is, that it strips excess nullbytes + inline std::string BitblockToString(const Block& bits) + { + // Decode to bytes + std::string text = BitblockToBytes(bits); + + // Dümp excess nullbytes + text.resize(strlen(text.data())); + + return text; + } + + //! Will convert a flexible data block to a bytestring + inline std::string BitsToBytes(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(); + } + + //! Will convert a flexible data block to a string + //! //! The difference to BitsToBytes() is, that it strips excess nullbytes + inline std::string BitsToString(const Flexblock& bits) + { + // Decode to bytes + std::string text = BitsToBytes(bits); + + // Dümp excess nullbytes + text.resize(strlen(text.data())); + + return text; + } + + //! Turns a fixed-size 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-size 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 = ((std::size_t)c - '0') + 0; + else if ((c >= 'a') && (c <= 'f')) + // Else, it is a lowercase letter + value = ((std::size_t)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 = ((std::size_t)c - '0') + 0; + else if ((c >= 'a') && (c <= 'f')) + // Else, it is a lowercase letter + value = ((std::size_t)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 BLOCK_SIZE from a password of arbitrary length. + //! Note that if your password is shorter (in bits) than BLOCK_SIZE, the rest of the key will be padded with 0 (see next line!). + //! To provide a better initial key, (and to get rid of padding zeroes), the raw result (b) will be xor'd with an initialization vector based on b. + //! : return b ^ iv(b) + inline Block PasswordToKey(const std::string& in) + { + // Let's provide a nice initial value to be sure even a password of length 0 results in a proper key + Block b = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); + + // 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) + { + const Block fragment = StringToBitblock( + PadStringToLength(in.substr(i, BLOCK_SIZE / 8), BLOCK_SIZE / 8, 0, false) + ); + + // To provide confusion, xor the blocks together + // To provide diffusion, hash fragment to fragment' first + b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + } + + + return b; + } + + //! Will reduce a flexblock (they are of arbitrary length) to a single block. + //! This single block should change completely, if a single bit in the input flexblock changes anywhere. + inline Block ReductionFunction_Flexblock2Block(const Flexblock& in) + { + Block b; // No initialization vector needed here + + // Segment the input in segments of BLOCK_SIZE, and xor them together. + for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE) + { + const Block fragment = Block(PadStringToLength(in.substr(i, BLOCK_SIZE), BLOCK_SIZE, 0, false)); + + // To provide confusion, xor the blocks together + // To provide diffusion, hash fragment to fragment' first + b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); + } + + 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 = BitsToBytes(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; + } +}