1// rng.cpp - written and placed in the public domain by Wei Dai 2 3#include "pch.h" 4 5#include "rng.h" 6#include "fips140.h" 7 8#include <time.h> 9#include <math.h> 10 11NAMESPACE_BEGIN(CryptoPP) 12 13// linear congruential generator 14// originally by William S. England 15 16// do not use for cryptographic purposes 17 18/* 19** Original_numbers are the original published m and q in the 20** ACM article above. John Burton has furnished numbers for 21** a reportedly better generator. The new numbers are now 22** used in this program by default. 23*/ 24 25#ifndef LCRNG_ORIGINAL_NUMBERS 26const word32 LC_RNG::m=2147483647L; 27const word32 LC_RNG::q=44488L; 28 29const word16 LC_RNG::a=(unsigned int)48271L; 30const word16 LC_RNG::r=3399; 31#else 32const word32 LC_RNG::m=2147483647L; 33const word32 LC_RNG::q=127773L; 34 35const word16 LC_RNG::a=16807; 36const word16 LC_RNG::r=2836; 37#endif 38 39void LC_RNG::GenerateBlock(byte *output, size_t size) 40{ 41 while (size--) 42 { 43 word32 hi = seed/q; 44 word32 lo = seed%q; 45 46 long test = a*lo - r*hi; 47 48 if (test > 0) 49 seed = test; 50 else 51 seed = test+ m; 52 53 *output++ = (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)); 54 } 55} 56 57// ******************************************************** 58 59#ifndef CRYPTOPP_IMPORTS 60 61X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector) 62 : cipher(c), 63 S(cipher->BlockSize()), 64 dtbuf(S), 65 randseed(seed, S), 66 m_lastBlock(S), 67 m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? S : 0) 68{ 69 if (!deterministicTimeVector) 70 { 71 time_t tstamp1 = time(0); 72 xorbuf(dtbuf, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), S)); 73 cipher->ProcessBlock(dtbuf); 74 clock_t tstamp2 = clock(); 75 xorbuf(dtbuf, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), S)); 76 cipher->ProcessBlock(dtbuf); 77 } 78 79 // for FIPS 140-2 80 GenerateBlock(m_lastBlock, S); 81} 82 83void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) 84{ 85 while (size > 0) 86 { 87 // calculate new enciphered timestamp 88 if (m_deterministicTimeVector.size()) 89 { 90 cipher->ProcessBlock(m_deterministicTimeVector, dtbuf); 91 IncrementCounterByOne(m_deterministicTimeVector, S); 92 } 93 else 94 { 95 clock_t c = clock(); 96 xorbuf(dtbuf, (byte *)&c, UnsignedMin(sizeof(c), S)); 97 time_t t = time(NULL); 98 xorbuf(dtbuf+S-UnsignedMin(sizeof(t), S), (byte *)&t, UnsignedMin(sizeof(t), S)); 99 cipher->ProcessBlock(dtbuf); 100 } 101 102 // combine enciphered timestamp with seed 103 xorbuf(randseed, dtbuf, S); 104 105 // generate a new block of random bytes 106 cipher->ProcessBlock(randseed); 107 if (memcmp(m_lastBlock, randseed, S) == 0) 108 throw SelfTestFailure("X917RNG: Continuous random number generator test failed."); 109 110 // output random bytes 111 size_t len = UnsignedMin(S, size); 112 target.ChannelPut(channel, randseed, len); 113 size -= len; 114 115 // compute new seed vector 116 memcpy(m_lastBlock, randseed, S); 117 xorbuf(randseed, dtbuf, S); 118 cipher->ProcessBlock(randseed); 119 } 120} 121 122#endif 123 124MaurerRandomnessTest::MaurerRandomnessTest() 125 : sum(0.0), n(0) 126{ 127 for (unsigned i=0; i<V; i++) 128 tab[i] = 0; 129} 130 131size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) 132{ 133 while (length--) 134 { 135 byte inByte = *inString++; 136 if (n >= Q) 137 sum += log(double(n - tab[inByte])); 138 tab[inByte] = n; 139 n++; 140 } 141 return 0; 142} 143 144double MaurerRandomnessTest::GetTestValue() const 145{ 146 if (BytesNeeded() > 0) 147 throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed"); 148 149 double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer 150 151 double value = fTu * 0.1392; // arbitrarily normalize it to 152 return value > 1.0 ? 1.0 : value; // a number between 0 and 1 153} 154 155NAMESPACE_END 156