1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
// 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)
{
memset(m_datetime, 0x00, m_size);
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 (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
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
|