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 |
---|