/src/botan/build/include/botan/rng.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Random Number Generator base classes |
3 | | * (C) 1999-2009,2015,2016 Jack Lloyd |
4 | | * |
5 | | * Botan is released under the Simplified BSD License (see license.txt) |
6 | | */ |
7 | | |
8 | | #ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_ |
9 | | #define BOTAN_RANDOM_NUMBER_GENERATOR_H_ |
10 | | |
11 | | #include <botan/secmem.h> |
12 | | #include <botan/exceptn.h> |
13 | | #include <botan/mutex.h> |
14 | | #include <type_traits> |
15 | | #include <chrono> |
16 | | #include <string> |
17 | | |
18 | | namespace Botan { |
19 | | |
20 | | class Entropy_Sources; |
21 | | |
22 | | /** |
23 | | * An interface to a cryptographic random number generator |
24 | | */ |
25 | | class BOTAN_PUBLIC_API(2,0) RandomNumberGenerator |
26 | | { |
27 | | public: |
28 | 332 | virtual ~RandomNumberGenerator() = default; |
29 | | |
30 | 332 | RandomNumberGenerator() = default; |
31 | | |
32 | | /* |
33 | | * Never copy a RNG, create a new one |
34 | | */ |
35 | | RandomNumberGenerator(const RandomNumberGenerator& rng) = delete; |
36 | | RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete; |
37 | | |
38 | | /** |
39 | | * Randomize a byte array. |
40 | | * |
41 | | * May block shortly if e.g. the RNG is not yet initialized |
42 | | * or a retry because of insufficient entropy is needed. |
43 | | * |
44 | | * @param output the byte array to hold the random output. |
45 | | * @param length the length of the byte array output in bytes. |
46 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
47 | | * @throws Exception if the RNG fails |
48 | | */ |
49 | | virtual void randomize(uint8_t output[], size_t length) = 0; |
50 | | |
51 | | /** |
52 | | * Returns false if it is known that this RNG object is not able to accept |
53 | | * externally provided inputs (via add_entropy, randomize_with_input, etc). |
54 | | * In this case, any such provided inputs are ignored. |
55 | | * |
56 | | * If this function returns true, then inputs may or may not be accepted. |
57 | | */ |
58 | | virtual bool accepts_input() const = 0; |
59 | | |
60 | | /** |
61 | | * Incorporate some additional data into the RNG state. For |
62 | | * example adding nonces or timestamps from a peer's protocol |
63 | | * message can help hedge against VM state rollback attacks. |
64 | | * A few RNG types do not accept any externally provided input, |
65 | | * in which case this function is a no-op. |
66 | | * |
67 | | * @param input a byte array containg the entropy to be added |
68 | | * @param length the length of the byte array in |
69 | | * @throws Exception may throw if the RNG accepts input, but adding the entropy failed. |
70 | | */ |
71 | | virtual void add_entropy(const uint8_t input[], size_t length) = 0; |
72 | | |
73 | | /** |
74 | | * Incorporate some additional data into the RNG state. |
75 | | */ |
76 | | template<typename T> void add_entropy_T(const T& t) |
77 | | { |
78 | | static_assert(std::is_standard_layout<T>::value && std::is_trivial<T>::value, "add_entropy_T data must be POD"); |
79 | | this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T)); |
80 | | } |
81 | | |
82 | | /** |
83 | | * Incorporate entropy into the RNG state then produce output. |
84 | | * Some RNG types implement this using a single operation, default |
85 | | * calls add_entropy + randomize in sequence. |
86 | | * |
87 | | * Use this to further bind the outputs to your current |
88 | | * process/protocol state. For instance if generating a new key |
89 | | * for use in a session, include a session ID or other such |
90 | | * value. See NIST SP 800-90 A, B, C series for more ideas. |
91 | | * |
92 | | * @param output buffer to hold the random output |
93 | | * @param output_len size of the output buffer in bytes |
94 | | * @param input entropy buffer to incorporate |
95 | | * @param input_len size of the input buffer in bytes |
96 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
97 | | * @throws Exception if the RNG fails |
98 | | * @throws Exception may throw if the RNG accepts input, but adding the entropy failed. |
99 | | */ |
100 | | virtual void randomize_with_input(uint8_t output[], size_t output_len, |
101 | | const uint8_t input[], size_t input_len); |
102 | | |
103 | | /** |
104 | | * This calls `randomize_with_input` using some timestamps as extra input. |
105 | | * |
106 | | * For a stateful RNG using non-random but potentially unique data the |
107 | | * extra input can help protect against problems with fork, VM state |
108 | | * rollback, or other cases where somehow an RNG state is duplicated. If |
109 | | * both of the duplicated RNG states later incorporate a timestamp (and the |
110 | | * timestamps don't themselves repeat), their outputs will diverge. |
111 | | * |
112 | | * @param output buffer to hold the random output |
113 | | * @param output_len size of the output buffer in bytes |
114 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
115 | | * @throws Exception if the RNG fails |
116 | | * @throws Exception may throw if the RNG accepts input, but adding the entropy failed. |
117 | | */ |
118 | | virtual void randomize_with_ts_input(uint8_t output[], size_t output_len); |
119 | | |
120 | | /** |
121 | | * @return the name of this RNG type |
122 | | */ |
123 | | virtual std::string name() const = 0; |
124 | | |
125 | | /** |
126 | | * Clear all internally held values of this RNG |
127 | | * @post is_seeded() == false if the RNG has an internal state that can be cleared. |
128 | | */ |
129 | | virtual void clear() = 0; |
130 | | |
131 | | /** |
132 | | * Check whether this RNG is seeded. |
133 | | * @return true if this RNG was already seeded, false otherwise. |
134 | | */ |
135 | | virtual bool is_seeded() const = 0; |
136 | | |
137 | | /** |
138 | | * Poll provided sources for up to poll_bits bits of entropy |
139 | | * or until the timeout expires. Returns estimate of the number |
140 | | * of bits collected. |
141 | | * |
142 | | * Sets the seeded state to true if enough entropy was added. |
143 | | */ |
144 | | virtual size_t reseed(Entropy_Sources& srcs, |
145 | | size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, |
146 | | std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT); |
147 | | |
148 | | /** |
149 | | * Reseed by reading specified bits from the RNG |
150 | | * |
151 | | * Sets the seeded state to true if enough entropy was added. |
152 | | * |
153 | | * @throws Exception if RNG accepts input but reseeding failed. |
154 | | */ |
155 | | virtual void reseed_from_rng(RandomNumberGenerator& rng, |
156 | | size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS); |
157 | | |
158 | | // Some utility functions built on the interface above: |
159 | | |
160 | | /** |
161 | | * Return a random vector |
162 | | * @param bytes number of bytes in the result |
163 | | * @return randomized vector of length bytes |
164 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
165 | | * @throws Exception if the RNG fails |
166 | | */ |
167 | | secure_vector<uint8_t> random_vec(size_t bytes) |
168 | 551k | { |
169 | 551k | secure_vector<uint8_t> output; |
170 | 551k | random_vec(output, bytes); |
171 | 551k | return output; |
172 | 551k | } |
173 | | |
174 | | template<typename Alloc> |
175 | | void random_vec(std::vector<uint8_t, Alloc>& v, size_t bytes) |
176 | 557k | { |
177 | 557k | v.resize(bytes); |
178 | 557k | this->randomize(v.data(), v.size()); |
179 | 557k | } void Botan::RandomNumberGenerator::random_vec<Botan::secure_allocator<unsigned char> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long) Line | Count | Source | 176 | 557k | { | 177 | 557k | v.resize(bytes); | 178 | 557k | this->randomize(v.data(), v.size()); | 179 | 557k | } |
void Botan::RandomNumberGenerator::random_vec<std::__1::allocator<unsigned char> >(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long) Line | Count | Source | 176 | 362 | { | 177 | 362 | v.resize(bytes); | 178 | 362 | this->randomize(v.data(), v.size()); | 179 | 362 | } |
|
180 | | |
181 | | /** |
182 | | * Return a random byte |
183 | | * @return random byte |
184 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
185 | | * @throws Exception if the RNG fails |
186 | | */ |
187 | | uint8_t next_byte() |
188 | 0 | { |
189 | 0 | uint8_t b; |
190 | 0 | this->randomize(&b, 1); |
191 | 0 | return b; |
192 | 0 | } |
193 | | |
194 | | /** |
195 | | * @return a random byte that is greater than zero |
196 | | * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy |
197 | | * @throws Exception if the RNG fails |
198 | | */ |
199 | | uint8_t next_nonzero_byte() |
200 | 0 | { |
201 | 0 | uint8_t b = this->next_byte(); |
202 | 0 | while(b == 0) |
203 | 0 | b = this->next_byte(); |
204 | 0 | return b; |
205 | 0 | } |
206 | | }; |
207 | | |
208 | | /** |
209 | | * Convenience typedef |
210 | | */ |
211 | | typedef RandomNumberGenerator RNG; |
212 | | |
213 | | /** |
214 | | * Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG) |
215 | | */ |
216 | | class BOTAN_PUBLIC_API(2,0) Hardware_RNG : public RandomNumberGenerator |
217 | | { |
218 | | public: |
219 | 0 | virtual void clear() final override { /* no way to clear state of hardware RNG */ } |
220 | | }; |
221 | | |
222 | | /** |
223 | | * Null/stub RNG - fails if you try to use it for anything |
224 | | * This is not generally useful except for in certain tests |
225 | | */ |
226 | | class BOTAN_PUBLIC_API(2,0) Null_RNG final : public RandomNumberGenerator |
227 | | { |
228 | | public: |
229 | 0 | bool is_seeded() const override { return false; } |
230 | | |
231 | 0 | bool accepts_input() const override { return false; } |
232 | | |
233 | 0 | void clear() override {} |
234 | | |
235 | | void randomize(uint8_t[], size_t) override |
236 | 0 | { |
237 | 0 | throw PRNG_Unseeded("Null_RNG called"); |
238 | 0 | } |
239 | | |
240 | 0 | void add_entropy(const uint8_t[], size_t) override {} |
241 | | |
242 | 0 | std::string name() const override { return "Null_RNG"; } |
243 | | }; |
244 | | |
245 | | #if defined(BOTAN_TARGET_OS_HAS_THREADS) |
246 | | /** |
247 | | * Wraps access to a RNG in a mutex |
248 | | * Note that most of the time it's much better to use a RNG per thread |
249 | | * otherwise the RNG will act as an unnecessary contention point |
250 | | * |
251 | | * Since 2.16.0 all Stateful_RNG instances have an internal lock, so |
252 | | * this class is no longer needed. It will be removed in a future major |
253 | | * release. |
254 | | */ |
255 | | class BOTAN_PUBLIC_API(2,0) Serialized_RNG final : public RandomNumberGenerator |
256 | | { |
257 | | public: |
258 | | void randomize(uint8_t out[], size_t len) override |
259 | 0 | { |
260 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
261 | 0 | m_rng->randomize(out, len); |
262 | 0 | } |
263 | | |
264 | | bool accepts_input() const override |
265 | 0 | { |
266 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
267 | 0 | return m_rng->accepts_input(); |
268 | 0 | } |
269 | | |
270 | | bool is_seeded() const override |
271 | 0 | { |
272 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
273 | 0 | return m_rng->is_seeded(); |
274 | 0 | } |
275 | | |
276 | | void clear() override |
277 | 0 | { |
278 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
279 | 0 | m_rng->clear(); |
280 | 0 | } |
281 | | |
282 | | std::string name() const override |
283 | 0 | { |
284 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
285 | 0 | return m_rng->name(); |
286 | 0 | } |
287 | | |
288 | | size_t reseed(Entropy_Sources& src, |
289 | | size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS, |
290 | | std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override |
291 | 0 | { |
292 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
293 | 0 | return m_rng->reseed(src, poll_bits, poll_timeout); |
294 | 0 | } |
295 | | |
296 | | void add_entropy(const uint8_t in[], size_t len) override |
297 | 0 | { |
298 | 0 | lock_guard_type<mutex_type> lock(m_mutex); |
299 | 0 | m_rng->add_entropy(in, len); |
300 | 0 | } |
301 | | |
302 | | /** |
303 | | * Since 2.16.0 this is no longer needed for any RNG type. This |
304 | | * class will be removed in a future major release. |
305 | | */ |
306 | | BOTAN_DEPRECATED("Use version accepting a unique_ptr") |
307 | 0 | explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {} |
308 | | |
309 | | /** |
310 | | * Since 2.16.0 this is no longer needed for any RNG type. This |
311 | | * class will be removed in a future major release. |
312 | | */ |
313 | 0 | explicit Serialized_RNG(std::unique_ptr<RandomNumberGenerator> rng) : m_rng(std::move(rng)) {} |
314 | | |
315 | | private: |
316 | | mutable mutex_type m_mutex; |
317 | | std::unique_ptr<RandomNumberGenerator> m_rng; |
318 | | }; |
319 | | #endif |
320 | | |
321 | | } |
322 | | |
323 | | #endif |