| 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 | |
|---|
| 11 | NAMESPACE_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 |
|---|
| 26 | const word32 LC_RNG::m=2147483647L; |
|---|
| 27 | const word32 LC_RNG::q=44488L; |
|---|
| 28 | |
|---|
| 29 | const word16 LC_RNG::a=(unsigned int)48271L; |
|---|
| 30 | const word16 LC_RNG::r=3399; |
|---|
| 31 | #else |
|---|
| 32 | const word32 LC_RNG::m=2147483647L; |
|---|
| 33 | const word32 LC_RNG::q=127773L; |
|---|
| 34 | |
|---|
| 35 | const word16 LC_RNG::a=16807; |
|---|
| 36 | const word16 LC_RNG::r=2836; |
|---|
| 37 | #endif |
|---|
| 38 | |
|---|
| 39 | void 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++ = byte((GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3))); |
|---|
| 54 | } |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | // ******************************************************** |
|---|
| 58 | |
|---|
| 59 | #ifndef CRYPTOPP_IMPORTS |
|---|
| 60 | |
|---|
| 61 | X917RNG::X917RNG(BlockTransformation *c, const byte *seed, const byte *deterministicTimeVector) |
|---|
| 62 | : m_cipher(c), |
|---|
| 63 | m_size(m_cipher->BlockSize()), |
|---|
| 64 | m_datetime(m_size), |
|---|
| 65 | m_randseed(seed, m_size), |
|---|
| 66 | m_lastBlock(m_size), |
|---|
| 67 | m_deterministicTimeVector(deterministicTimeVector, deterministicTimeVector ? m_size : 0) |
|---|
| 68 | { |
|---|
| 69 | // Valgrind finding, http://github.com/weidai11/cryptopp/issues/105 |
|---|
| 70 | // Garbage in the tail creates a non-conforming X9.17 or X9.31 generator. |
|---|
| 71 | if (m_size > 8) |
|---|
| 72 | { |
|---|
| 73 | memset(m_datetime, 0x00, m_size); |
|---|
| 74 | memset(m_lastBlock, 0x00, m_size); |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | if (!deterministicTimeVector) |
|---|
| 78 | { |
|---|
| 79 | time_t tstamp1 = time(0); |
|---|
| 80 | xorbuf(m_datetime, (byte *)&tstamp1, UnsignedMin(sizeof(tstamp1), m_size)); |
|---|
| 81 | m_cipher->ProcessBlock(m_datetime); |
|---|
| 82 | clock_t tstamp2 = clock(); |
|---|
| 83 | xorbuf(m_datetime, (byte *)&tstamp2, UnsignedMin(sizeof(tstamp2), m_size)); |
|---|
| 84 | m_cipher->ProcessBlock(m_datetime); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | // for FIPS 140-2 |
|---|
| 88 | GenerateBlock(m_lastBlock, m_size); |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | void X917RNG::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) |
|---|
| 92 | { |
|---|
| 93 | while (size > 0) |
|---|
| 94 | { |
|---|
| 95 | // calculate new enciphered timestamp |
|---|
| 96 | if (m_deterministicTimeVector.size()) |
|---|
| 97 | { |
|---|
| 98 | m_cipher->ProcessBlock(m_deterministicTimeVector, m_datetime); |
|---|
| 99 | IncrementCounterByOne(m_deterministicTimeVector, m_size); |
|---|
| 100 | } |
|---|
| 101 | else |
|---|
| 102 | { |
|---|
| 103 | clock_t c = clock(); |
|---|
| 104 | xorbuf(m_datetime, (byte *)&c, UnsignedMin(sizeof(c), m_size)); |
|---|
| 105 | time_t t = time(NULL); |
|---|
| 106 | xorbuf(m_datetime+m_size-UnsignedMin(sizeof(t), m_size), (byte *)&t, UnsignedMin(sizeof(t), m_size)); |
|---|
| 107 | m_cipher->ProcessBlock(m_datetime); |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | // combine enciphered timestamp with seed |
|---|
| 111 | xorbuf(m_randseed, m_datetime, m_size); |
|---|
| 112 | |
|---|
| 113 | // generate a new block of random bytes |
|---|
| 114 | m_cipher->ProcessBlock(m_randseed); |
|---|
| 115 | if (memcmp(m_lastBlock, m_randseed, m_size) == 0) |
|---|
| 116 | throw SelfTestFailure("X917RNG: Continuous random number generator test failed."); |
|---|
| 117 | |
|---|
| 118 | // output random bytes |
|---|
| 119 | size_t len = UnsignedMin(m_size, size); |
|---|
| 120 | target.ChannelPut(channel, m_randseed, len); |
|---|
| 121 | size -= len; |
|---|
| 122 | |
|---|
| 123 | // compute new seed vector |
|---|
| 124 | memcpy(m_lastBlock, m_randseed, m_size); |
|---|
| 125 | xorbuf(m_randseed, m_datetime, m_size); |
|---|
| 126 | m_cipher->ProcessBlock(m_randseed); |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | #endif |
|---|
| 131 | |
|---|
| 132 | MaurerRandomnessTest::MaurerRandomnessTest() |
|---|
| 133 | : sum(0.0), n(0) |
|---|
| 134 | { |
|---|
| 135 | for (unsigned i=0; i<V; i++) |
|---|
| 136 | tab[i] = 0; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | size_t MaurerRandomnessTest::Put2(const byte *inString, size_t length, int /*messageEnd*/, bool /*blocking*/) |
|---|
| 140 | { |
|---|
| 141 | while (length--) |
|---|
| 142 | { |
|---|
| 143 | byte inByte = *inString++; |
|---|
| 144 | if (n >= Q) |
|---|
| 145 | sum += log(double(n - tab[inByte])); |
|---|
| 146 | tab[inByte] = n; |
|---|
| 147 | n++; |
|---|
| 148 | } |
|---|
| 149 | return 0; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | double MaurerRandomnessTest::GetTestValue() const |
|---|
| 153 | { |
|---|
| 154 | if (BytesNeeded() > 0) |
|---|
| 155 | throw Exception(Exception::OTHER_ERROR, "MaurerRandomnessTest: " + IntToString(BytesNeeded()) + " more bytes of input needed"); |
|---|
| 156 | |
|---|
| 157 | double fTu = (sum/(n-Q))/log(2.0); // this is the test value defined by Maurer |
|---|
| 158 | |
|---|
| 159 | double value = fTu * 0.1392; // arbitrarily normalize it to |
|---|
| 160 | return value > 1.0 ? 1.0 : value; // a number between 0 and 1 |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | NAMESPACE_END |
|---|