Crypto++
|
00001 // rng.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 00005 #include "rng.h" 00006 #include "fips140.h" 00007 00008 #include <time.h> 00009 #include <math.h> 00010 00011 NAMESPACE_BEGIN(CryptoPP) 00012 00013 // linear congruential generator 00014 // originally by William S. England 00015 00016 // do not use for cryptographic purposes 00017 00018 /* 00019 ** Original_numbers are the original published m and q in the 00020 ** ACM article above. John Burton has furnished numbers for 00021 ** a reportedly better generator. The new numbers are now 00022 ** used in this program by default. 00023 */ 00024 00025 #ifndef LCRNG_ORIGINAL_NUMBERS 00026 const word32 LC_RNG::m=2147483647L; 00027 const word32 LC_RNG::q=44488L; 00028 00029 const word16 LC_RNG::a=(unsigned int)48271L; 00030 const word16 LC_RNG::r=3399; 00031 #else 00032 const word32 LC_RNG::m=2147483647L; 00033 const word32 LC_RNG::q=127773L; 00034 00035 const word16 LC_RNG::a=16807; 00036 const word16 LC_RNG::r=2836; 00037 #endif 00038 00039 void LC_RNG::GenerateBlock(byte *output, size_t size) 00040 { 00041 while (size--) 00042 { 00043 word32 hi = seed/q; 00044 word32 lo = seed%q; 00045 00046 long test = a*lo - r*hi; 00047 00048 if (test > 0) 00049 seed = test; 00050 else 00051 seed = test+ m; 00052 00053 *output++ = (GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3)); 00054 } 00055 } 00056 00057 // ******************************************************** 00058 00059 #ifndef CRYPTOPP_IMPORTS 00060 00061 X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector) 00062 : cipher(c), 00063 S(cipher->BlockSize()), 00064 dtbuf(S), 00065 randseed(seed, S), 00066 m_lastBlock(S), 00067 m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? S : 0) 00068 { 00069 if (!deterministicTimeVector) 00070 { 00071 time_t tstamp1 = time(0); 00072 xorbuf(dtbuf, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), S)); 00073 cipher->ProcessBlock(dtbuf); 00074 clock_t tstamp2 = clock(); 00075 xorbuf(dtbuf, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), S)); 00076 cipher->ProcessBlock(dtbuf); 00077 } 00078 00079 // for FIPS 140-2 00080 GenerateBlock(m_lastBlock, S); 00081 } 00082 00083 void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) 00084 { 00085 while (size > 0) 00086 { 00087 // calculate new enciphered timestamp 00088 if (m_deterministicTimeVector.size()) 00089 { 00090 cipher->ProcessBlock(m_deterministicTimeVector, dtbuf); 00091 IncrementCounterByOne(m_deterministicTimeVector, S); 00092 } 00093 else 00094 { 00095 clock_t c = clock(); 00096 xorbuf(dtbuf, (byte *)&c, UnsignedMin(sizeof(c), S)); 00097 time_t t = time(NULL); 00098 xorbuf(dtbuf+S-UnsignedMin(sizeof(t), S), (byte *)&t, UnsignedMin(sizeof(t), S)); 00099 cipher->ProcessBlock(dtbuf); 00100 } 00101 00102 // combine enciphered timestamp with seed 00103 xorbuf(randseed, dtbuf, S); 00104 00105 // generate a new block of random bytes 00106 cipher->ProcessBlock(randseed); 00107 if (memcmp(m_lastBlock, randseed, S) == 0) 00108 throw SelfTestFailure("X917RNG: Continuous random number generator test failed."); 00109 00110 // output random bytes 00111 size_t len = UnsignedMin(S, size); 00112 target.ChannelPut(channel, randseed, len); 00113 size -= len; 00114 00115 // compute new seed vector 00116 memcpy(m_lastBlock, randseed, S); 00117 xorbuf(randseed, dtbuf, S); 00118 cipher->ProcessBlock(randseed); 00119 } 00120 } 00121 00122 #endif 00123 00124 MaurerRandomnessTest::MaurerRandomnessTest() 00125 : sum(0.0), n(0) 00126 { 00127 for (unsigned i=0; i<V; i++) 00128 tab[i] = 0; 00129 } 00130 00131 size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) 00132 { 00133 while (length--) 00134 { 00135 byte inByte = *inString++; 00136 if (n >= Q) 00137 sum += log(double(n - tab[inByte])); 00138 tab[inByte] = n; 00139 n++; 00140 } 00141 return 0; 00142 } 00143 00144 double MaurerRandomnessTest::GetTestValue() const 00145 { 00146 if (BytesNeeded() > 0) 00147 throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed"); 00148 00149 double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer 00150 00151 double value = fTu * 0.1392; // arbitrarily normalize it to 00152 return value > 1.0 ? 1.0 : value; // a number between 0 and 1 00153 } 00154 00155 NAMESPACE_END