/src/cryptopp/randpool.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // randpool.cpp - originally written and placed in the public domain by Wei Dai |
2 | | // RandomPool used to follow the design of randpool in PGP 2.6.x, |
3 | | // but as of version 5.5 it has been redesigned to reduce the risk |
4 | | // of reusing random numbers after state rollback (which may occur |
5 | | // when running in a virtual machine like VMware). |
6 | | |
7 | | #include "pch.h" |
8 | | |
9 | | #ifndef CRYPTOPP_IMPORTS |
10 | | |
11 | | #include "randpool.h" |
12 | | #include "aes.h" |
13 | | #include "sha.h" |
14 | | #include "hrtimer.h" |
15 | | #include "trap.h" |
16 | | |
17 | | // OldRandomPool |
18 | | #include "mdc.h" |
19 | | #include "modes.h" |
20 | | |
21 | | #include <time.h> |
22 | | |
23 | | NAMESPACE_BEGIN(CryptoPP) |
24 | | |
25 | | RandomPool::RandomPool() |
26 | | : m_pCipher(new AES::Encryption), m_keySet(false) |
27 | 28 | { |
28 | 28 | std::memset(m_key, 0, m_key.SizeInBytes()); |
29 | 28 | std::memset(m_seed, 0, m_seed.SizeInBytes()); |
30 | 28 | } |
31 | | |
32 | | void RandomPool::IncorporateEntropy(const byte *input, size_t length) |
33 | 28 | { |
34 | 28 | SHA256 hash; |
35 | 28 | hash.Update(m_key, 32); |
36 | 28 | hash.Update(input, length); |
37 | 28 | hash.Final(m_key); |
38 | 28 | m_keySet = false; |
39 | 28 | } |
40 | | |
41 | | void RandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) |
42 | 0 | { |
43 | 0 | if (size > 0) |
44 | 0 | { |
45 | 0 | if (!m_keySet) |
46 | 0 | m_pCipher->SetKey(m_key, 32); |
47 | |
|
48 | 0 | CRYPTOPP_COMPILE_ASSERT(sizeof(TimerWord) <= 16); |
49 | 0 | CRYPTOPP_COMPILE_ASSERT(sizeof(time_t) <= 8); |
50 | |
|
51 | 0 | Timer timer; |
52 | 0 | TimerWord tw = timer.GetCurrentTimerValue(); |
53 | |
|
54 | 0 | *(TimerWord *)(void*)m_seed.data() += tw; |
55 | 0 | time_t t = time(NULLPTR); |
56 | | |
57 | | // UBsan finding: signed integer overflow: 1876017710 + 1446085457 cannot be represented in type 'long int' |
58 | | // *(time_t *)(m_seed.data()+8) += t; |
59 | 0 | word64 tt1 = 0, tt2 = (word64)t; |
60 | 0 | std::memcpy(&tt1, m_seed.data()+8, 8); |
61 | 0 | std::memcpy(m_seed.data()+8, &(tt2 += tt1), 8); |
62 | | |
63 | | // Wipe the intermediates |
64 | 0 | *((volatile TimerWord*)&tw) = 0; |
65 | 0 | *((volatile word64*)&tt1) = 0; |
66 | 0 | *((volatile word64*)&tt2) = 0; |
67 | |
|
68 | 0 | do |
69 | 0 | { |
70 | 0 | m_pCipher->ProcessBlock(m_seed); |
71 | 0 | size_t len = UnsignedMin(16u, size); |
72 | 0 | target.ChannelPut(channel, m_seed, len); |
73 | 0 | size -= len; |
74 | 0 | } while (size > 0); |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | // OldRandomPool is provided for backwards compatibility for a migration path |
79 | | typedef MDC<SHA1> OldRandomPoolCipher; |
80 | | |
81 | | OldRandomPool::OldRandomPool(unsigned int poolSize) |
82 | | : pool(poolSize), key(OldRandomPoolCipher::DEFAULT_KEYLENGTH), addPos(0), getPos(poolSize) |
83 | 0 | { |
84 | 0 | CRYPTOPP_ASSERT(poolSize > key.size()); |
85 | 0 | std::memset(pool, 0, poolSize); |
86 | 0 | std::memset(key, 0, key.size()); |
87 | 0 | } |
88 | | |
89 | | void OldRandomPool::IncorporateEntropy(const byte *input, size_t length) |
90 | 0 | { |
91 | 0 | size_t t; |
92 | 0 | while (length > (t = pool.size() - addPos)) |
93 | 0 | { |
94 | 0 | xorbuf(pool+addPos, input, t); |
95 | 0 | input += t; |
96 | 0 | length -= t; |
97 | 0 | Stir(); |
98 | 0 | } |
99 | |
|
100 | 0 | if (length) |
101 | 0 | { |
102 | 0 | xorbuf(pool+addPos, input, length); |
103 | 0 | addPos += length; |
104 | 0 | getPos = pool.size(); // Force stir on get |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | | // GenerateWord32 is overridden and provides Crypto++ 5.4 behavior. |
109 | | // Taken from RandomNumberGenerator::GenerateWord32 in cryptlib.cpp. |
110 | | word32 OldRandomPool::GenerateWord32 (word32 min, word32 max) |
111 | 0 | { |
112 | 0 | const word32 range = max-min; |
113 | 0 | const unsigned int maxBytes = BytePrecision(range); |
114 | 0 | const unsigned int maxBits = BitPrecision(range); |
115 | |
|
116 | 0 | word32 value; |
117 | |
|
118 | 0 | do |
119 | 0 | { |
120 | 0 | value = 0; |
121 | 0 | for (unsigned int i=0; i<maxBytes; i++) |
122 | 0 | value = (value << 8) | GenerateByte(); |
123 | |
|
124 | 0 | value = Crop(value, maxBits); |
125 | 0 | } while (value > range); |
126 | |
|
127 | 0 | return value+min; |
128 | 0 | } |
129 | | |
130 | | void OldRandomPool::Stir() |
131 | 0 | { |
132 | 0 | CFB_Mode<OldRandomPoolCipher>::Encryption cipher; |
133 | |
|
134 | 0 | for (int i=0; i<2; i++) |
135 | 0 | { |
136 | 0 | cipher.SetKeyWithIV(key, key.size(), pool.end()-cipher.IVSize()); |
137 | 0 | cipher.ProcessString(pool, pool.size()); |
138 | 0 | std::memcpy(key, pool, key.size()); |
139 | 0 | } |
140 | |
|
141 | 0 | addPos = 0; |
142 | 0 | getPos = key.size(); |
143 | 0 | } |
144 | | |
145 | | void OldRandomPool::GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size) |
146 | 0 | { |
147 | 0 | while (size > 0) |
148 | 0 | { |
149 | 0 | if (getPos == pool.size()) |
150 | 0 | Stir(); |
151 | 0 | size_t t = UnsignedMin(pool.size() - getPos, size); |
152 | 0 | target.ChannelPut(channel, pool+getPos, t); |
153 | 0 | size -= t; |
154 | 0 | getPos += t; |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | | byte OldRandomPool::GenerateByte() |
159 | 0 | { |
160 | 0 | if (getPos == pool.size()) |
161 | 0 | Stir(); |
162 | |
|
163 | 0 | return pool[getPos++]; |
164 | 0 | } |
165 | | |
166 | | void OldRandomPool::GenerateBlock(byte *outString, size_t size) |
167 | 0 | { |
168 | 0 | ArraySink sink(outString, size); |
169 | 0 | GenerateIntoBufferedTransformation(sink, DEFAULT_CHANNEL, size); |
170 | 0 | } |
171 | | |
172 | | NAMESPACE_END |
173 | | |
174 | | #endif |