Update documentation for PasswordToKey function

This commit is contained in:
Leon Etienne 2022-05-13 11:37:08 +02:00
parent 754db08e7d
commit 5afd772a84

View File

@ -1,320 +1,319 @@
#pragma once #pragma once
#include <bitset> #include <bitset>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <cstring> #include <cstring>
#include "SecureBitset.h" #include "SecureBitset.h"
#include "Block.h" #include "Block.h"
#include "Flexblock.h" #include "Flexblock.h"
#include "Config.h" #include "Config.h"
#include "Cipher.h" #include "Cipher.h"
#include "InitializationVector.h" #include "InitializationVector.h"
namespace GhettoCipher namespace GhettoCipher
{ {
//! Mod-operator that works with negative values //! Mod-operator that works with negative values
inline int Mod(const int numerator, const int denominator) inline int Mod(const int numerator, const int denominator)
{ {
return (denominator + (numerator % denominator)) % denominator; return (denominator + (numerator % denominator)) % denominator;
} }
//! Will perform a wrapping left-bitshift on a bitset //! Will perform a wrapping left-bitshift on a bitset
template <std::size_t T> template <std::size_t T>
inline SecureBitset<T> Shiftl(const SecureBitset<T>& bits, const std::size_t amount) inline SecureBitset<T> Shiftl(const SecureBitset<T>& bits, const std::size_t amount)
{ {
std::stringstream ss; std::stringstream ss;
const std::string bitss = bits.to_string(); const std::string bitss = bits.to_string();
for (std::size_t i = 0; i < bitss.size(); i++) for (std::size_t i = 0; i < bitss.size(); i++)
ss << bitss[Mod((int)(i + amount), (int)bitss.size())]; ss << bitss[Mod((int)(i + amount), (int)bitss.size())];
return SecureBitset<T>(ss.str()); return SecureBitset<T>(ss.str());
} }
//! Will perform a wrapping right-bitshift on a bitset //! Will perform a wrapping right-bitshift on a bitset
template <std::size_t T> template <std::size_t T>
inline SecureBitset<T> Shiftr(const SecureBitset<T>& bits, const std::size_t amount) inline SecureBitset<T> Shiftr(const SecureBitset<T>& bits, const std::size_t amount)
{ {
std::stringstream ss; std::stringstream ss;
const std::string bitss = bits.to_string(); const std::string bitss = bits.to_string();
for (std::size_t i = 0; i < bitss.size(); i++) for (std::size_t i = 0; i < bitss.size(); i++)
ss << bitss[Mod((i - amount), bitss.size())]; ss << bitss[Mod((i - amount), bitss.size())];
return SecureBitset<T>(ss.str()); return SecureBitset<T>(ss.str());
} }
//! Will pad a string to a set length with a certain character //! 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) 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 // Fast-reject: Already above padded length
if (str.length() >= len) if (str.length() >= len)
return str; return str;
std::stringstream ss; std::stringstream ss;
// Pad left: // Pad left:
if (padLeft) if (padLeft)
{ {
for (std::size_t i = 0; i < len - str.size(); i++) for (std::size_t i = 0; i < len - str.size(); i++)
ss << pad; ss << pad;
ss << str; ss << str;
} }
// Pad right: // Pad right:
else else
{ {
ss << str; ss << str;
for (std::size_t i = 0; i < len - str.size(); i++) for (std::size_t i = 0; i < len - str.size(); i++)
ss << pad; ss << pad;
} }
return ss.str(); return ss.str();
} }
//! Will convert a string to a fixed-size data block //! Will convert a string to a fixed-size data block
inline Block StringToBitblock(const std::string& s) inline Block StringToBitblock(const std::string& s)
{ {
std::stringstream ss; std::stringstream ss;
for (std::size_t i = 0; i < s.size(); i++) for (std::size_t i = 0; i < s.size(); i++)
ss << std::bitset<8>(s[i]); ss << std::bitset<8>(s[i]);
// Pad rest with zeores // Pad rest with zeores
return Block(PadStringToLength(ss.str(), 128, '0', false)); return Block(PadStringToLength(ss.str(), 128, '0', false));
} }
//! Will convert a string to a flexible data block //! Will convert a string to a flexible data block
inline Flexblock StringToBits(const std::string& s) inline Flexblock StringToBits(const std::string& s)
{ {
std::stringstream ss; std::stringstream ss;
for (std::size_t i = 0; i < s.size(); i++) for (std::size_t i = 0; i < s.size(); i++)
ss << std::bitset<8>(s[i]); ss << std::bitset<8>(s[i]);
return Flexblock(ss.str()); return Flexblock(ss.str());
} }
//! Will convert a fixed-size data block to a bytestring //! Will convert a fixed-size data block to a bytestring
inline std::string BitblockToBytes(const Block& bits) inline std::string BitblockToBytes(const Block& bits)
{ {
std::stringstream ss; std::stringstream ss;
const std::string bitstring = bits.to_string(); const std::string bitstring = bits.to_string();
for (std::size_t i = 0; i < BLOCK_SIZE; i += 8) for (std::size_t i = 0; i < BLOCK_SIZE; i += 8)
{ {
ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong();
} }
return ss.str(); return ss.str();
} }
//! Will convert a fixed-size data block to a string //! Will convert a fixed-size data block to a string
//! The difference to BitblockToBytes() is, that it strips excess nullbytes //! The difference to BitblockToBytes() is, that it strips excess nullbytes
inline std::string BitblockToString(const Block& bits) inline std::string BitblockToString(const Block& bits)
{ {
// Decode to bytes // Decode to bytes
std::string text = BitblockToBytes(bits); std::string text = BitblockToBytes(bits);
// Dümp excess nullbytes // Dümp excess nullbytes
text.resize(strlen(text.data())); text.resize(strlen(text.data()));
return text; return text;
} }
//! Will convert a flexible data block to a bytestring //! Will convert a flexible data block to a bytestring
inline std::string BitsToBytes(const Flexblock& bits) inline std::string BitsToBytes(const Flexblock& bits)
{ {
std::stringstream ss; std::stringstream ss;
const std::string bitstring = bits; const std::string bitstring = bits;
for (std::size_t i = 0; i < bits.size(); i += 8) for (std::size_t i = 0; i < bits.size(); i += 8)
{ {
ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong(); ss << (char)std::bitset<8>(bitstring.substr(i, 8)).to_ulong();
} }
return ss.str(); return ss.str();
} }
//! Will convert a flexible data block to a string //! Will convert a flexible data block to a string
//! //! The difference to BitsToBytes() is, that it strips excess nullbytes //! //! The difference to BitsToBytes() is, that it strips excess nullbytes
inline std::string BitsToString(const Flexblock& bits) inline std::string BitsToString(const Flexblock& bits)
{ {
// Decode to bytes // Decode to bytes
std::string text = BitsToBytes(bits); std::string text = BitsToBytes(bits);
// Dümp excess nullbytes // Dümp excess nullbytes
text.resize(strlen(text.data())); text.resize(strlen(text.data()));
return text; return text;
} }
//! Turns a fixed-size data block into a hex-string //! Turns a fixed-size data block into a hex-string
inline std::string BitblockToHexstring(const Block& b) inline std::string BitblockToHexstring(const Block& b)
{ {
std::stringstream ss; std::stringstream ss;
const std::string charset = "0123456789abcdef"; const std::string charset = "0123456789abcdef";
const std::string bstr = b.to_string(); const std::string bstr = b.to_string();
for (std::size_t i = 0; i < bstr.size(); i += 4) for (std::size_t i = 0; i < bstr.size(); i += 4)
ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()];
return ss.str(); return ss.str();
} }
//! Turns a flexible data block into a hex-string //! Turns a flexible data block into a hex-string
inline std::string BitsToHexstring(const Flexblock& b) inline std::string BitsToHexstring(const Flexblock& b)
{ {
std::stringstream ss; std::stringstream ss;
const std::string charset = "0123456789abcdef"; const std::string charset = "0123456789abcdef";
const std::string bstr = b; const std::string bstr = b;
for (std::size_t i = 0; i < bstr.size(); i += 4) for (std::size_t i = 0; i < bstr.size(); i += 4)
ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()]; ss << charset[std::bitset<4>(bstr.substr(i, 4)).to_ulong()];
return ss.str(); return ss.str();
} }
//! Turns a hex string into a fixed-size data block //! Turns a hex string into a fixed-size data block
inline Block HexstringToBitblock(const std::string& hexstring) inline Block HexstringToBitblock(const std::string& hexstring)
{ {
std::stringstream ss; std::stringstream ss;
for (std::size_t i = 0; i < hexstring.size(); i++) for (std::size_t i = 0; i < hexstring.size(); i++)
{ {
const char c = hexstring[i]; const char c = hexstring[i];
// Get value // Get value
std::size_t value; std::size_t value;
if ((c >= '0') && (c <= '9')) if ((c >= '0') && (c <= '9'))
// Is it a number? // Is it a number?
value = ((std::size_t)c - '0') + 0; value = ((std::size_t)c - '0') + 0;
else if ((c >= 'a') && (c <= 'f')) else if ((c >= 'a') && (c <= 'f'))
// Else, it is a lowercase letter // Else, it is a lowercase letter
value = ((std::size_t)c - 'a') + 10; value = ((std::size_t)c - 'a') + 10;
else else
throw std::logic_error("non-hex string detected in HexstringToBits()"); throw std::logic_error("non-hex string detected in HexstringToBits()");
// Append to our bits // Append to our bits
ss << std::bitset<4>(value); ss << std::bitset<4>(value);
} }
return Block(ss.str()); return Block(ss.str());
} }
//! Turns a hex string into a flexible data block //! Turns a hex string into a flexible data block
inline Flexblock HexstringToBits(const std::string& hexstring) inline Flexblock HexstringToBits(const std::string& hexstring)
{ {
std::stringstream ss; std::stringstream ss;
for (std::size_t i = 0; i < hexstring.size(); i++) for (std::size_t i = 0; i < hexstring.size(); i++)
{ {
const char c = hexstring[i]; const char c = hexstring[i];
// Get value // Get value
std::size_t value; std::size_t value;
if ((c >= '0') && (c <= '9')) if ((c >= '0') && (c <= '9'))
// Is it a number? // Is it a number?
value = ((std::size_t)c - '0') + 0; value = ((std::size_t)c - '0') + 0;
else if ((c >= 'a') && (c <= 'f')) else if ((c >= 'a') && (c <= 'f'))
// Else, it is a lowercase letter // Else, it is a lowercase letter
value = ((std::size_t)c - 'a') + 10; value = ((std::size_t)c - 'a') + 10;
else else
throw std::logic_error("non-hex string detected in HexstringToBits()"); throw std::logic_error("non-hex string detected in HexstringToBits()");
// Append to our bits // Append to our bits
ss << std::bitset<4>(value); ss << std::bitset<4>(value);
} }
return ss.str(); return ss.str();
} }
//! Creates a key of size BLOCK_SIZE from a password of arbitrary length. //! 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!).
//! 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.
//! 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)
//! : return b ^ iv(b) inline Block PasswordToKey(const std::string& in)
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
// 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"));
Block b = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN"));
// Segment the password in segments of key-size, and xor them together.
// 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)
for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE / 8) {
{ const Block fragment = StringToBitblock(
const Block fragment = StringToBitblock( PadStringToLength(in.substr(i, BLOCK_SIZE / 8), BLOCK_SIZE / 8, 0, false)
PadStringToLength(in.substr(i, BLOCK_SIZE / 8), BLOCK_SIZE / 8, 0, false) );
);
// To provide confusion, xor the blocks together
// To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first
// To provide diffusion, hash fragment to fragment' first b ^= Block(Cipher(fragment).Encipher(fragment.to_string()));
b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); }
}
return b;
return b; }
}
//! Will reduce a flexblock (they are of arbitrary length) to a single block.
//! 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.
//! This single block should change completely, if a single bit in the input flexblock changes anywhere. inline Block ReductionFunction_Flexblock2Block(const Flexblock& in)
inline Block ReductionFunction_Flexblock2Block(const Flexblock& in) {
{ Block b; // No initialization vector needed here
Block b; // No initialization vector needed here
// Segment the input in segments of BLOCK_SIZE, and xor them together.
// Segment the input in segments of BLOCK_SIZE, and xor them together. for (std::size_t i = 0; i < in.size(); i += BLOCK_SIZE)
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));
const Block fragment = Block(PadStringToLength(in.substr(i, BLOCK_SIZE), BLOCK_SIZE, 0, false));
// To provide confusion, xor the blocks together
// To provide confusion, xor the blocks together // To provide diffusion, hash fragment to fragment' first
// To provide diffusion, hash fragment to fragment' first b ^= Block(Cipher(fragment).Encipher(fragment.to_string()));
b ^= Block(Cipher(fragment).Encipher(fragment.to_string())); }
}
return b;
return b; }
}
//! Will read a file into a flexblock
//! Will read a file into a flexblock inline Flexblock ReadFileToBits(const std::string& filepath)
inline Flexblock ReadFileToBits(const std::string& filepath) {
{ // Read file
// Read file std::ifstream ifs(filepath, std::ios::binary);
std::ifstream ifs(filepath, std::ios::binary);
if (!ifs.good())
if (!ifs.good()) throw std::runtime_error("Unable to open ifilestream!");
throw std::runtime_error("Unable to open ifilestream!");
std::stringstream ss;
std::stringstream ss; std::copy(
std::copy( std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(),
std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(ss)
std::ostreambuf_iterator<char>(ss) );
);
ifs.close();
ifs.close();
const std::string bytes = ss.str();
const std::string bytes = ss.str();
// Convert bytes to bits
// Convert bytes to bits return StringToBits(bytes);
return StringToBits(bytes); }
}
//! Will save bits to a binary file
//! Will save bits to a binary file inline void WriteBitsToFile(const std::string& filepath, const Flexblock& bits)
inline void WriteBitsToFile(const std::string& filepath, const Flexblock& bits) {
{ // Convert bits to bytes
// Convert bits to bytes const std::string bytes = BitsToBytes(bits);
const std::string bytes = BitsToBytes(bits);
// Write bits to file
// Write bits to file std::ofstream ofs(filepath, std::ios::binary);
std::ofstream ofs(filepath, std::ios::binary);
if (!ofs.good())
if (!ofs.good()) throw std::runtime_error("Unable to open ofilestream!");
throw std::runtime_error("Unable to open ofilestream!");
ofs.write(bytes.data(), bytes.length());
ofs.write(bytes.data(), bytes.length()); ofs.close();
ofs.close();
return;
return; }
} }
}