diff --git a/GCryptLib/include/GCrypt/Hasher.h b/GCryptLib/include/GCrypt/Hasher.h new file mode 100644 index 0000000..55e8483 --- /dev/null +++ b/GCryptLib/include/GCrypt/Hasher.h @@ -0,0 +1,34 @@ +#ifndef GCRYPT_HASHER_H +#define GCRYPT_HASHER_H + +#include "GCrypt/Flexblock.h" +#include "GCrypt/Block.h" +#include "GCrypt/Cipher.h" + +namespace Leonetienne::GCrypt { + /** This class implements a hash function, based on the GCrypt cipher + */ + class Hasher { + public: + Hasher(); + + //! Will add the hash value of `data` to the hashsum + void Digest(const Block& data); + + //! Will return the current hashsum + const Block& GetHashsum() const; + + //! Will calculate a hashsum for `data`. + static Block CalculateHashsum(const Flexblock& data); + + private: + //! The cipher to use + Cipher cipher; + + //! The current state of the hashsum + Block block; + }; +} + +#endif + diff --git a/GCryptLib/include/GCrypt/Util.h b/GCryptLib/include/GCrypt/Util.h index 01019e0..789f540 100644 --- a/GCryptLib/include/GCrypt/Util.h +++ b/GCryptLib/include/GCrypt/Util.h @@ -1,4 +1,6 @@ -#pragma once +#ifndef GCRYPT_UTIL_H +#define GCRYPT_UTIL_H + #include #include #include @@ -78,7 +80,7 @@ namespace Leonetienne::GCrypt { } // Pad rest with zeores - return Block(PadStringToLength(ss.str(), 128, '0', false)); + return Block(PadStringToLength(ss.str(), BLOCK_SIZE, '0', false)); } //! Will convert a string to a flexible data block @@ -226,43 +228,7 @@ namespace Leonetienne::GCrypt { } //! 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, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(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, Cipher::CIPHER_DIRECTION::ENCIPHER).Digest(fragment).to_string()); - } - - return b; - } + Block PasswordToKey(const std::string& in); //! Will read a file into a flexblock inline Flexblock ReadFileToBits(const std::string& filepath) { @@ -307,3 +273,5 @@ namespace Leonetienne::GCrypt { } } +#endif + diff --git a/GCryptLib/src/Hasher.cpp b/GCryptLib/src/Hasher.cpp new file mode 100644 index 0000000..7767bdd --- /dev/null +++ b/GCryptLib/src/Hasher.cpp @@ -0,0 +1,57 @@ +#include "GCrypt/Hasher.h" +#include "GCrypt/Util.h" +#include "GCrypt/InitializationVector.h" + +namespace Leonetienne::GCrypt { + + Hasher::Hasher() : + // Initialize our cipher with a static, but randomly distributed key. + cipher( + StringToBitblock("CfRtNdMTP4Y5CWRd"), + Cipher::CIPHER_DIRECTION::ENCIPHER + ) { + block = InitializationVector(StringToBitblock("3J7IipfQTDJbO8jtasz9PgWui6faPaEMOuVuAqyhB1S2CRcLw5caawewgDUEG1WN")); + + return; + } + + void Hasher::Digest(const Block& data) { + // Encipher the current block, and xor it on the current hashsum + block ^= cipher.Digest(data); + return; + } + + const Block& Hasher::GetHashsum() const { + return block; + } + + Block Hasher::CalculateHashsum(const Flexblock& data) { + // 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)) + ); + } + + // Add an additional block, containing the length of the input + std::stringstream ss; + ss << data.length(); + const Block lengthBlock = StringToBitblock(ss.str()); + blocks.push_back(lengthBlock); + + // Create hasher instance + Hasher hasher; + + // Digest all blocks + for (Block& block : blocks) { + hasher.Digest(block); + } + + // Return the total hashsum + return hasher.GetHashsum(); + } + +} + diff --git a/GCryptLib/src/Util.cpp b/GCryptLib/src/Util.cpp new file mode 100644 index 0000000..11f2179 --- /dev/null +++ b/GCryptLib/src/Util.cpp @@ -0,0 +1,13 @@ +#include "GCrypt/Util.h" +#include "GCrypt/Hasher.h" + +namespace Leonetienne::GCrypt { + Block PasswordToKey(const std::string& in) { + // We already have a hashing algorithm, so why not use it + // Yeah, this won't work, because it would create an include loop. This method needs to be outsourced to a cpp file.. + + const Block hashedPassword = Hasher::CalculateHashsum(StringToBits(in)); + return hashedPassword; + } +} +