rng.cpp

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

Generated on Fri Jun 1 11:11:24 2007 for Crypto++ by  doxygen 1.5.2