diff --git a/GCryptLib/include/GCrypt/Feistel.h b/GCryptLib/include/GCrypt/Feistel.h index 9063d0a..586d131 100644 --- a/GCryptLib/include/GCrypt/Feistel.h +++ b/GCryptLib/include/GCrypt/Feistel.h @@ -26,6 +26,8 @@ namespace Leonetienne::GCrypt { //! Will decipher a data block via the set seed-key Block Decipher(const Block& data); + void operator=(const Feistel& other); + private: //! Will run the feistel rounds, with either regular key //! order or reversed key order diff --git a/GCryptLib/include/GCrypt/GCipher.h b/GCryptLib/include/GCrypt/GCipher.h index 2764341..5228ecf 100644 --- a/GCryptLib/include/GCrypt/GCipher.h +++ b/GCryptLib/include/GCrypt/GCipher.h @@ -23,8 +23,10 @@ namespace Leonetienne::GCrypt { //! Will digest a data block, and return it Block Digest(const Block& input); + void operator=(const GCipher& other); + private: - const DIRECTION direction; + DIRECTION direction; //! The feistel instance to be used Feistel feistel; diff --git a/GCryptLib/include/GCrypt/GHash.h b/GCryptLib/include/GCrypt/GHash.h index bf5301f..f962529 100644 --- a/GCryptLib/include/GCrypt/GHash.h +++ b/GCryptLib/include/GCrypt/GHash.h @@ -24,6 +24,8 @@ namespace Leonetienne::GCrypt { //! Will calculate a hashsum for `data`. static Block CalculateHashsum(const Flexblock& data); + void operator=(const GHash& other); + private: //! The cipher to use GCipher cipher; diff --git a/GCryptLib/include/GCrypt/GPrng.h b/GCryptLib/include/GCrypt/GPrng.h new file mode 100644 index 0000000..99e9a6a --- /dev/null +++ b/GCryptLib/include/GCrypt/GPrng.h @@ -0,0 +1,63 @@ +#ifndef GCRYPT_GPRNG_H +#define GCRYPT_GPRNG_H + +#include "GCrypt/GHash.h" +#include "GCrypt/Util.h" +#include +#include +#include + +namespace Leonetienne::GCrypt { + /** This class implements a pseudo random number generator, based on the GCrypt hash function + */ + class GPrng { + public: + //! Will instanciate the prng with a seed. Seed could also be a GCrypt::Key. + GPrng(const Block& seed); + + //! Will instanciate the GPrng with no seed. You should really seed it later. + GPrng(); + + //! Will reset and seed the prng. Seed could also be a GCrypt::Key. + void Seed(const Block& seed); + + //! Will return a random bit. + bool GetBit(); + + //! Will return a randomized instance of any primitive. + template + T GetRandom() { + static_assert(std::is_fundamental::value, "Leonetienne::GCrypt::GPrng::GetRandom() may only be used with primitive types!"); + + // Pull the required amount of bits + std::stringstream ss; + for (std::size_t i = 0; i < sizeof(T)*8; i++) { + ss << GetBit() ? '1' : '0'; + } + + // Transform to bytes + const std::string bytes = BitsToBytes(ss.str()); + + // Cram bytes into type + T t; + memcpy(&t, bytes.data(), sizeof(T)); + + // Return our randomized primitive + return t; + } + + //! Will return a random block + Block GetBlock(); + + private: + //! Will generate the next block of random bits + void AdvanceBlock(); + + GHash hasher; + Block seed; + std::size_t nextBit = 0; + }; +} + +#endif + diff --git a/GCryptLib/src/Feistel.cpp b/GCryptLib/src/Feistel.cpp index dd14dc4..6301eb5 100644 --- a/GCryptLib/src/Feistel.cpp +++ b/GCryptLib/src/Feistel.cpp @@ -240,6 +240,12 @@ namespace Leonetienne::GCrypt { return; } + void Feistel::operator=(const Feistel& other) { + roundKeys = other.roundKeys; + + return; + } + // These pragmas only work for MSVC and g++, as far as i know. Beware!!! #if defined _WIN32 || defined _WIN64 #pragma optimize("", off ) diff --git a/GCryptLib/src/GCipher.cpp b/GCryptLib/src/GCipher.cpp index 10cebab..103011d 100644 --- a/GCryptLib/src/GCipher.cpp +++ b/GCryptLib/src/GCipher.cpp @@ -50,5 +50,14 @@ namespace Leonetienne::GCrypt { throw std::runtime_error("Unreachable branch reached."); } + + void GCipher::operator=(const GCipher& other) { + direction = other.direction; + feistel = other.feistel; + lastBlock = other.lastBlock; + + return; + } + } diff --git a/GCryptLib/src/GHash.cpp b/GCryptLib/src/GHash.cpp index 666580d..dec8f6c 100644 --- a/GCryptLib/src/GHash.cpp +++ b/GCryptLib/src/GHash.cpp @@ -55,5 +55,10 @@ namespace Leonetienne::GCrypt { return hasher.GetHashsum(); } + void GHash::operator=(const GHash& other) { + cipher = other.cipher; + + return; + } } diff --git a/GCryptLib/src/GPrng.cpp b/GCryptLib/src/GPrng.cpp new file mode 100644 index 0000000..371761d --- /dev/null +++ b/GCryptLib/src/GPrng.cpp @@ -0,0 +1,75 @@ +#include "GCrypt/GPrng.h" +#include + +namespace Leonetienne::GCrypt { + + GPrng::GPrng(const Block& seed) { + this->seed = seed; + hasher.DigestBlock(seed); + } + + GPrng::GPrng() { + } + + void GPrng::Seed(const Block& seed) { + hasher = GHash(); + this->seed = seed; + hasher.DigestBlock(seed); + + return; + } + + bool GPrng::GetBit() { + // If we have no more bits to go, create new ones + if (nextBit >= BLOCK_SIZE) { + AdvanceBlock(); + } + + // Return the next bit. + return hasher.GetHashsum()[nextBit++]; + } + + void GPrng::AdvanceBlock() { + // To prevent an attacker from being able + // to predict block n, by knowing block n-1, and block n-2, + // we will advance the hash function by block n-1 XOR seed. + // This way it is impossible for an attacker to know the + // state of the hash function, unless the seed is known. + + // Advance the block (Add the current hashsum XOR seed to the hasher) + hasher.DigestBlock(Block(hasher.GetHashsum() ^ seed)); + + // Reset the pointer + nextBit = 0; + + return; + } + + Block GPrng::GetBlock() { + // Getting a block is a bit troublesome. + // Just fetching 512 bits would be too much of a performance hog. + + // Slurp up the rest of the current block + std::stringstream ss; + const std::size_t bitsLeft = BLOCK_SIZE - nextBit; + ss << hasher.GetHashsum().to_string().substr(nextBit, bitsLeft); + + // Now we have to advance to the next block + AdvanceBlock(); + + // Now, grab the remaining bits + const std::size_t remainingBits = BLOCK_SIZE - bitsLeft; + ss << hasher.GetHashsum().to_string().substr(0, remainingBits); + + // Assert that we have the correct number of bits + assert(ss.str().length() == BLOCK_SIZE); + + // Set out bitpointer + nextBit = remainingBits; + + // Return our block + return Block(ss.str()); + } + +} +