rng.cpp
// rng.cpp - originally written and placed in the public domain by Wei Dai
#include "pch.h"
#include "rng.h"
#include "fips140.h"
#include <time.h>
#include <math.h>
NAMESPACE_BEGIN(CryptoPP)
// linear congruential generator
// originally by William S. England
// do not use for cryptographic purposes
/*
** Original_numbers are the original published m and q in the
** ACM article above. John Burton has furnished numbers for
** a reportedly better generator. The new numbers are now
** used in this program by default.
*/
#ifndef LCRNG_ORIGINAL_NUMBERS
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=44488L;
const word16 LC_RNG::a=(unsigned int)48271L;
const word16 LC_RNG::r=3399;
#else
const word32 LC_RNG::m=2147483647L;
const word32 LC_RNG::q=127773L;
const word16 LC_RNG::a=16807;
const word16 LC_RNG::r=2836;
#endif
void LC_RNG::GenerateBlock(byte *output, size_t size)
{
while (size--)
{
const word32 hi = seed/q;
const word32 lo = seed%q;
const sword64 test = a*lo - r*hi;
if (test > 0)
seed = static_cast<word32>(test);
else
seed = static_cast<word32>(test + m);
*output++ = byte((GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)));
}
}
// ********************************************************
#ifndef CRYPTOPP_IMPORTS
X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector)
: m_cipher(c),
m_size(m_cipher->BlockSize()),
m_datetime(m_size),
m_randseed(seed, m_size),
m_lastBlock(m_size),
m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? m_size : 0)
{
// Valgrind finding, http://github.com/weidai11/cryptopp/issues/105
// Garbage in the tail creates a non-conforming X9.17 or X9.31 generator.
if (m_size > 8)
{
std::memset(m_datetime, 0x00, m_size);
std::memset(m_lastBlock, 0x00, m_size);
}
if (!deterministicTimeVector)
{
time_t tstamp1 = ::time(NULLPTR);
xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size));
m_cipher->ProcessBlock(m_datetime);
clock_t tstamp2 = clock();
xorbuf(m_datetime, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), m_size));
m_cipher->ProcessBlock(m_datetime);
}
// for FIPS 140-2
// GenerateBlock(m_lastBlock, m_size);
// Make explicit call to avoid virtual-dispatch findings in ctor
ArraySink target(m_lastBlock, m_size);
X917RNG::GenerateIntoBufferedTransformation(target, DEFAULT_CHANNEL, m_size);
}
void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
{
while (size > 0)
{
// calculate new enciphered timestamp
if (m_deterministicTimeVector.size())
{
m_cipher->ProcessBlock(m_deterministicTimeVector, m_datetime);
IncrementCounterByOne(m_deterministicTimeVector, m_size);
}
else
{
clock_t c = clock();
xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size));
time_t t = ::time(NULLPTR);
xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size));
m_cipher->ProcessBlock(m_datetime);
}
// combine enciphered timestamp with seed
xorbuf(m_randseed, m_datetime, m_size);
// generate a new block of random bytes
m_cipher->ProcessBlock(m_randseed);
if (std::memcmp(m_lastBlock, m_randseed, m_size) == 0)
throw SelfTestFailure("X917RNG: Continuous random number generator test failed.");
// output random bytes
size_t len = UnsignedMin(m_size, size);
target.ChannelPut(channel, m_randseed, len);
size -= len;
// compute new seed vector
std::memcpy(m_lastBlock, m_randseed, m_size);
xorbuf(m_randseed, m_datetime, m_size);
m_cipher->ProcessBlock(m_randseed);
}
}
#endif
MaurerRandomnessTest::MaurerRandomnessTest()
: sum(0.0), n(0)
{
for (unsigned i=0; i<V; i++)
tab[i] = 0;
}
size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int /*messageEnd*/, bool /*blocking*/)
{
while (length--)
{
byte inByte = *inString++;
if (n >= Q)
sum += ::log(double(n - tab[inByte]));
tab[inByte] = n;
n++;
}
return 0;
}
double MaurerRandomnessTest::GetTestValue() const
{
if (BytesNeeded() > 0)
throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed");
double fTu = (sum/(n-Q))/::log(2.0); // this is the test value defined by Maurer
double value = fTu * 0.1392; // arbitrarily normalize it to
return value > 1.0 ? 1.0 : value; // a number between 0 and 1
}
NAMESPACE_END
BlockTransformation
Interface for the data processing part of block ciphers.
Definition cryptlib.h:861
BufferedTransformation
Interface for buffered transformations.
Definition cryptlib.h:1657
BufferedTransformation::ChannelPut
size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true)
Input a byte for processing on a channel.
Definition cryptlib.h:2199
Exception
Base class for all exceptions thrown by the library.
Definition cryptlib.h:164
Exception::OTHER_ERROR
@ OTHER_ERROR
Some other error occurred not belonging to other categories.
Definition cryptlib.h:182
LC_RNG::GenerateBlock
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition rng.cpp:39
MaurerRandomnessTest::MaurerRandomnessTest
MaurerRandomnessTest()
Construct a MaurerRandomnessTest.
Definition rng.cpp:135
MaurerRandomnessTest::BytesNeeded
unsigned int BytesNeeded() const
Provides the number of bytes of input is needed by the test.
Definition rng.h:96
MaurerRandomnessTest::Put2
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
Input multiple bytes for processing.
Definition rng.cpp:142
X917RNG::GenerateIntoBufferedTransformation
void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size)
Generate random bytes into a BufferedTransformation.
X917RNG::X917RNG
X917RNG(BlockTransformation *cipher, const byte *seed, const byte *deterministicTimeVector=NULL)
Construct a X917RNG.
sword64
signed long long sword64
64-bit signed datatype
Definition config_int.h:109
byte
unsigned char byte
8-bit unsigned datatype
Definition config_int.h:66
word32
unsigned int word32
32-bit unsigned datatype
Definition config_int.h:72
word16
unsigned short word16
16-bit unsigned datatype
Definition config_int.h:69
lword
word64 lword
Large word type.
Definition config_int.h:168
DEFAULT_CHANNEL
const std::string DEFAULT_CHANNEL
Default channel for BufferedTransformation.
Definition cryptlib.h:516
fips140.h
Classes and functions for the FIPS 140-2 validated library.
IncrementCounterByOne
void IncrementCounterByOne(byte *inout, unsigned int size)
Performs an addition with carry on a block of bytes.
Definition misc.h:1508
IntToString
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition misc.h:929
UnsignedMin
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be negative and incorrectly promoted.
Definition misc.h:695
xorbuf
CRYPTOPP_DLL void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
CryptoPP
Crypto++ library namespace.
pch.h
Precompiled header file.
rng.h
Miscellaneous classes for RNGs.