Implemented GPrng pnrg

This commit is contained in:
Leonetienne 2022-05-22 16:54:40 +02:00
parent bedfc91e04
commit 04c67436c4
No known key found for this signature in database
GPG Key ID: C33879CD92E9708C
8 changed files with 165 additions and 1 deletions

View File

@ -26,6 +26,8 @@ namespace Leonetienne::GCrypt {
//! Will decipher a data block via the set seed-key //! Will decipher a data block via the set seed-key
Block Decipher(const Block& data); Block Decipher(const Block& data);
void operator=(const Feistel& other);
private: private:
//! Will run the feistel rounds, with either regular key //! Will run the feistel rounds, with either regular key
//! order or reversed key order //! order or reversed key order

View File

@ -23,8 +23,10 @@ namespace Leonetienne::GCrypt {
//! Will digest a data block, and return it //! Will digest a data block, and return it
Block Digest(const Block& input); Block Digest(const Block& input);
void operator=(const GCipher& other);
private: private:
const DIRECTION direction; DIRECTION direction;
//! The feistel instance to be used //! The feistel instance to be used
Feistel feistel; Feistel feistel;

View File

@ -24,6 +24,8 @@ namespace Leonetienne::GCrypt {
//! Will calculate a hashsum for `data`. //! Will calculate a hashsum for `data`.
static Block CalculateHashsum(const Flexblock& data); static Block CalculateHashsum(const Flexblock& data);
void operator=(const GHash& other);
private: private:
//! The cipher to use //! The cipher to use
GCipher cipher; GCipher cipher;

View File

@ -0,0 +1,63 @@
#ifndef GCRYPT_GPRNG_H
#define GCRYPT_GPRNG_H
#include "GCrypt/GHash.h"
#include "GCrypt/Util.h"
#include <string.h>
#include <sstream>
#include <type_traits>
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 <typename T>
T GetRandom() {
static_assert(std::is_fundamental<T>::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

View File

@ -240,6 +240,12 @@ namespace Leonetienne::GCrypt {
return; 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!!! // These pragmas only work for MSVC and g++, as far as i know. Beware!!!
#if defined _WIN32 || defined _WIN64 #if defined _WIN32 || defined _WIN64
#pragma optimize("", off ) #pragma optimize("", off )

View File

@ -50,5 +50,14 @@ namespace Leonetienne::GCrypt {
throw std::runtime_error("Unreachable branch reached."); throw std::runtime_error("Unreachable branch reached.");
} }
void GCipher::operator=(const GCipher& other) {
direction = other.direction;
feistel = other.feistel;
lastBlock = other.lastBlock;
return;
}
} }

View File

@ -55,5 +55,10 @@ namespace Leonetienne::GCrypt {
return hasher.GetHashsum(); return hasher.GetHashsum();
} }
void GHash::operator=(const GHash& other) {
cipher = other.cipher;
return;
}
} }

75
GCryptLib/src/GPrng.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "GCrypt/GPrng.h"
#include <cassert>
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());
}
}