Botan 3.13.0
Crypto and TLS for C&
rng.h
Go to the documentation of this file.
1/*
2* Random Number Generator base classes
3* (C) 1999-2009,2015,2016 Jack Lloyd
4* 2023 René Meusel - Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_
10#define BOTAN_RANDOM_NUMBER_GENERATOR_H_
11
12#include <botan/concepts.h>
13#include <botan/secmem.h>
14
15#include <array>
16#include <concepts>
17#include <span>
18#include <string>
19#include <type_traits>
20
21/*
22* We only include <chrono> in downstream applications to avoid
23* breaking semver wrt RandomNumberGenerator::reseed. Within the
24* library we avoid it because it slows down compilation significantly.
25*
26* TODO(Botan4): remove this entirely
27*/
28#if !defined(BOTAN_IS_BEING_BUILT)
29 #include <chrono>
30#endif
31
32namespace Botan {
33
34class Entropy_Sources;
35
36/**
37* An interface to a cryptographic random number generator
38*/
40 public:
41 /**
42 * Userspace RNGs like HMAC_DRBG will reseed after a specified number
43 * of outputs are generated. Set to zero to disable automatic reseeding.
44 */
45 static constexpr size_t DefaultReseedInterval = 1024;
46
47 /**
48 * Number of entropy bits polled for reseeding userspace RNGs like HMAC_DRBG
49 */
50 static constexpr size_t DefaultPollBits = 256;
51
52 virtual ~RandomNumberGenerator() = default;
53
54 /**
55 * Default constructor
56 */
58
59 /*
60 * Never copy a RNG, create a new one
61 */
64
65 /**
66 * Move constructor
67 */
69
70 /**
71 * Move assignment
72 * @return reference to this
73 */
75
76 /**
77 * Randomize a byte array.
78 *
79 * May block shortly if e.g. the RNG is not yet initialized
80 * or a retry because of insufficient entropy is needed.
81 *
82 * @param output the byte array to hold the random output.
83 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
84 * @throws Exception if the RNG fails
85 */
86 void randomize(std::span<uint8_t> output) { this->fill_bytes_with_input(output, {}); }
87
88 /**
89 * Randomize a byte array
90 * @param output the byte array to hold the random output
91 * @param length the number of bytes to generate
92 */
93 void randomize(uint8_t output[], size_t length) { this->randomize(std::span(output, length)); }
94
95 /**
96 * Returns false if it is known that this RNG object is not able to accept
97 * externally provided inputs (via add_entropy, randomize_with_input, etc).
98 * In this case, any such provided inputs are ignored.
99 *
100 * If this function returns true, then inputs may or may not be accepted.
101 */
102 virtual bool accepts_input() const = 0;
103
104 /**
105 * Incorporate some additional data into the RNG state. For
106 * example adding nonces or timestamps from a peer's protocol
107 * message can help hedge against VM state rollback attacks.
108 * A few RNG types do not accept any externally provided input,
109 * in which case this function is a no-op.
110 *
111 * @param input a byte array containing the entropy to be added
112 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
113 */
114 void add_entropy(std::span<const uint8_t> input) { this->fill_bytes_with_input({}, input); }
115
116 /**
117 * Incorporate some additional data into the RNG state
118 * @param input a byte array containing the entropy to be added
119 * @param length the number of bytes in input
120 */
121 void add_entropy(const uint8_t input[], size_t length) { this->add_entropy(std::span(input, length)); }
122
123 /**
124 * Incorporate some additional data into the RNG state.
125 */
126 template <typename T>
127 requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
128 void add_entropy_T(const T& t) {
129 this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
130 }
131
132 /**
133 * Incorporate entropy into the RNG state then produce output.
134 * Some RNG types implement this using a single operation, default
135 * calls add_entropy + randomize in sequence.
136 *
137 * Use this to further bind the outputs to your current
138 * process/protocol state. For instance if generating a new key
139 * for use in a session, include a session ID or other such
140 * value. See NIST SP 800-90 A, B, C series for more ideas.
141 *
142 * @param output buffer to hold the random output
143 * @param input entropy buffer to incorporate
144 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
145 * @throws Exception if the RNG fails
146 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
147 */
148 void randomize_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
149 this->fill_bytes_with_input(output, input);
150 }
151
152 /**
153 * Randomize a byte array, first incorporating additional input
154 * @param output the byte array to hold the random output
155 * @param output_len the number of bytes to generate
156 * @param input a byte array containing the entropy to be added
157 * @param input_len the number of bytes in input
158 */
159 void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) {
160 this->randomize_with_input(std::span(output, output_len), std::span(input, input_len));
161 }
162
163 /**
164 * This calls `randomize_with_input` using system specific values
165 *
166 * This first attempts to provide input to the underlying RNG from some system
167 * specific source. If a system RNG is available, it is queried and the output from
168 * the system RNG is used as the additional input. Otherwise 12 bytes consisting of
169 * the local clock plus the current process ID are used.
170 *
171 * For a stateful RNG that was already correctly seeded with sufficient
172 * cryptographically secure material, using non-random but potentially unique data
173 * as the extra input can help protect against problems with fork, VM state
174 * rollback, or other cases where somehow an RNG state is duplicated. If both of
175 * the duplicated RNG states later incorporate some input, even predictable input,
176 * their outputs will diverge.
177 *
178 * @param output buffer to hold the random output
179 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
180 * @throws Exception if the RNG fails
181 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
182 */
183 void randomize_with_ts_input(std::span<uint8_t> output);
184
185 /**
186 * Randomize a byte array, using timestamps as additional input
187 * @param output the byte array to hold the random output
188 * @param output_len the number of bytes to generate
189 */
190 void randomize_with_ts_input(uint8_t output[], size_t output_len) {
191 this->randomize_with_ts_input(std::span(output, output_len));
192 }
193
194 /**
195 * Return the name of this RNG type
196 * @return the name of this RNG type
197 */
198 virtual std::string name() const = 0;
199
200 /**
201 * Clear all internally held values of this RNG
202 * @post is_seeded() == false if the RNG has an internal state that can be cleared.
203 */
204 virtual void clear() = 0;
205
206 /**
207 * Check whether this RNG is seeded.
208 * @return true if this RNG was already seeded, false otherwise.
209 */
210 virtual bool is_seeded() const = 0;
211
212 /**
213 * Poll provided sources for up to poll_bits bits of entropy.
214 * Returns estimate of the number of bits collected.
215 * Sets the seeded state to true if enough entropy was added.
216 *
217 * @throws Exception if RNG accepts input but reseeding failed.
218 */
220 return reseed_from_sources(srcs, poll_bits);
221 }
222
223 /**
224 * Reseed by reading specified bits from the RNG
225 *
226 * Sets the seeded state to true if enough entropy was added.
227 *
228 * @throws Exception if RNG accepts input but reseeding failed.
229 */
231 return reseed_from_rng(rng, poll_bits);
232 }
233
234 // Some utility functions built on the interface above:
235
236 /**
237 * Fill a given byte container with @p bytes random bytes
238 *
239 * @todo deprecate this overload (in favor of randomize())
240 *
241 * @param v the container to be filled with @p bytes random bytes
242 * @throws Exception if RNG fails
243 */
244 void random_vec(std::span<uint8_t> v) { this->randomize(v); }
245
246 /**
247 * Resize a given byte container to @p bytes and fill it with random bytes
248 *
249 * @tparam T the desired byte container type (e.g std::vector<uint8_t>)
250 * @param v the container to be filled with @p bytes random bytes
251 * @param bytes number of random bytes to initialize the container with
252 * @throws Exception if RNG or memory allocation fails
253 */
254 template <concepts::resizable_byte_buffer T>
255 void random_vec(T& v, size_t bytes) {
256 v.resize(bytes);
257 random_vec(v);
258 }
259
260 /**
261 * Create some byte container type and fill it with some random @p bytes.
262 *
263 * @tparam T the desired byte container type (e.g std::vector<uint8_t>)
264 * @param bytes number of random bytes to initialize the container with
265 * @return a container of type T with @p bytes random bytes
266 * @throws Exception if RNG or memory allocation fails
267 */
268 template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
269 requires std::default_initializable<T>
270 T random_vec(size_t bytes) {
271 T result;
272 random_vec(result, bytes);
273 return result;
274 }
275
276 /**
277 * Create a std::array of @p bytes random bytes
278 */
279 template <size_t bytes>
280 std::array<uint8_t, bytes> random_array() {
281 std::array<uint8_t, bytes> result{};
282 random_vec(result);
283 return result;
284 }
285
286 /**
287 * Return a random byte
288 * @return random byte
289 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
290 * @throws Exception if the RNG fails
291 */
292 uint8_t next_byte() {
293 uint8_t b = 0;
294 this->fill_bytes_with_input(std::span(&b, 1), {});
295 return b;
296 }
297
298 /**
299 * Generate a single random byte which is not zero
300 * @return a random byte that is greater than zero
301 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
302 * @throws Exception if the RNG fails
303 */
305 uint8_t b = this->next_byte();
306 while(b == 0) {
307 b = this->next_byte();
308 }
309 return b;
310 }
311
312 /**
313 * Reseed by reading specified bits from the RNG
314 *
315 * Sets the seeded state to true if enough entropy was added.
316 *
317 * @throws Exception if RNG accepts input but reseeding failed.
318 */
319 virtual void reseed_from_rng(RandomNumberGenerator& rng,
320 size_t poll_bits = RandomNumberGenerator::DefaultPollBits);
321
322#if !defined(BOTAN_IS_BEING_BUILT)
323 /**
324 * Default poll timeout
325 */
326 static constexpr auto DefaultPollTimeout = std::chrono::milliseconds(50);
327
328 /**
329 * Poll provided sources for up to poll_bits bits of entropy.
330 * Returns estimate of the number of bits collected.
331 *
332 * Sets the seeded state to true if enough entropy was added.
333 *
334 * TODO(Botan4) remove this function
335 */
336 BOTAN_DEPRECATED("Use reseed_from_sources")
337 inline size_t reseed(Entropy_Sources& srcs,
338 size_t poll_bits = RandomNumberGenerator::DefaultPollBits,
339 std::chrono::milliseconds /*unused_timeout*/ = DefaultPollTimeout) {
340 return reseed_from(srcs, poll_bits);
341 }
342#endif
343
344 protected:
345 /**
346 * Poll provided sources for up to poll_bits bits of entropy.
347 * Returns estimate of the number of bits collected.
348 * Sets the seeded state to true if enough entropy was added.
349 *
350 * @throws Exception if RNG accepts input but reseeding failed.
351 */
352 virtual size_t reseed_from_sources(Entropy_Sources& srcs,
353 size_t poll_bits = RandomNumberGenerator::DefaultPollBits);
354
355 /**
356 * Generic interface to provide entropy to a concrete implementation and to
357 * fill a given buffer with random output. Both @p output and @p input may
358 * be empty and should be ignored in that case. If both buffers are
359 * non-empty implementations should typically first apply the @p input data
360 * and then generate random data into @p output.
361 *
362 * This method must be implemented by all RandomNumberGenerator sub-classes.
363 *
364 * @param output Byte buffer to write random bytes into. Implementations
365 * should not read from this buffer.
366 * @param input Byte buffer that may contain bytes to be incorporated in
367 * the RNG's internal state. Implementations may choose to
368 * ignore the bytes in this buffer.
369 */
370 virtual void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) = 0;
371};
372
373/**
374* Convenience typedef
375*/
377
378/**
379* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG)
380*/
382 public:
383 /**
384 * No-op clear implementation - no way to clear state of a hardware RNG
385 */
386 void clear() final {}
387};
388
389/**
390* Null/stub RNG - fails if you try to use it for anything
391* This is not generally useful except for in certain tests
392*/
394 public:
395 /**
396 * Test whether this RNG has been seeded
397 * @return true if this RNG is seeded and ready for use
398 */
399 bool is_seeded() const override { return false; }
400
401 /**
402 * Test whether this RNG accepts externally provided input
403 * @return false if this RNG is known to ignore provided inputs
404 */
405 bool accepts_input() const override { return false; }
406
407 /**
408 * Clear all internally held values of this RNG
409 */
410 void clear() override {}
411
412 /**
413 * Return the name of this RNG type
414 * @return the name of this RNG type
415 */
416 std::string name() const override { return "Null_RNG"; }
417
418 private:
419 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> /* ignored */) override;
420};
421
422} // namespace Botan
423
424#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
#define BOTAN_DEPRECATED(msg)
Definition api.h:73
void clear() final
Definition rng.h:386
bool accepts_input() const override
Definition rng.h:405
void clear() override
Definition rng.h:410
std::string name() const override
Definition rng.h:416
bool is_seeded() const override
Definition rng.h:399
void randomize(std::span< uint8_t > output)
Definition rng.h:86
RandomNumberGenerator & operator=(RandomNumberGenerator &&rng)=default
std::array< uint8_t, bytes > random_array()
Definition rng.h:280
virtual bool accepts_input() const =0
RandomNumberGenerator(RandomNumberGenerator &&rng)=default
virtual ~RandomNumberGenerator()=default
void add_entropy(std::span< const uint8_t > input)
Definition rng.h:114
virtual size_t reseed_from_sources(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.cpp:53
void randomize(uint8_t output[], size_t length)
Definition rng.h:93
uint8_t next_nonzero_byte()
Definition rng.h:304
static constexpr size_t DefaultPollBits
Definition rng.h:50
void random_vec(T &v, size_t bytes)
Definition rng.h:255
RandomNumberGenerator & operator=(const RandomNumberGenerator &rng)=delete
static constexpr size_t DefaultReseedInterval
Definition rng.h:45
static constexpr auto DefaultPollTimeout
Definition rng.h:326
virtual bool is_seeded() const =0
void randomize_with_ts_input(uint8_t output[], size_t output_len)
Definition rng.h:190
void add_entropy_T(const T &t)
Definition rng.h:128
void add_entropy(const uint8_t input[], size_t length)
Definition rng.h:121
virtual std::string name() const =0
virtual void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.cpp:65
void randomize_with_ts_input(std::span< uint8_t > output)
Definition rng.cpp:26
void random_vec(std::span< uint8_t > v)
Definition rng.h:244
T random_vec(size_t bytes)
Definition rng.h:270
size_t reseed_from(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.h:219
virtual void fill_bytes_with_input(std::span< uint8_t > output, std::span< const uint8_t > input)=0
void randomize_with_input(std::span< uint8_t > output, std::span< const uint8_t > input)
Definition rng.h:148
RandomNumberGenerator(const RandomNumberGenerator &rng)=delete
void reseed_from(RandomNumberGenerator &rng, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.h:230
void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len)
Definition rng.h:159
size_t reseed(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits, std::chrono::milliseconds=DefaultPollTimeout)
Definition rng.h:337
RandomNumberGenerator RNG
Definition rng.h:376