Botan 3.11.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
55
56 /*
57 * Never copy a RNG, create a new one
58 */
61
64
65 /**
66 * Randomize a byte array.
67 *
68 * May block shortly if e.g. the RNG is not yet initialized
69 * or a retry because of insufficient entropy is needed.
70 *
71 * @param output the byte array to hold the random output.
72 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
73 * @throws Exception if the RNG fails
74 */
75 void randomize(std::span<uint8_t> output) { this->fill_bytes_with_input(output, {}); }
76
77 void randomize(uint8_t output[], size_t length) { this->randomize(std::span(output, length)); }
78
79 /**
80 * Returns false if it is known that this RNG object is not able to accept
81 * externally provided inputs (via add_entropy, randomize_with_input, etc).
82 * In this case, any such provided inputs are ignored.
83 *
84 * If this function returns true, then inputs may or may not be accepted.
85 */
86 virtual bool accepts_input() const = 0;
87
88 /**
89 * Incorporate some additional data into the RNG state. For
90 * example adding nonces or timestamps from a peer's protocol
91 * message can help hedge against VM state rollback attacks.
92 * A few RNG types do not accept any externally provided input,
93 * in which case this function is a no-op.
94 *
95 * @param input a byte array containing the entropy to be added
96 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
97 */
98 void add_entropy(std::span<const uint8_t> input) { this->fill_bytes_with_input({}, input); }
99
100 void add_entropy(const uint8_t input[], size_t length) { this->add_entropy(std::span(input, length)); }
101
102 /**
103 * Incorporate some additional data into the RNG state.
104 */
105 template <typename T>
106 requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
107 void add_entropy_T(const T& t) {
108 this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
109 }
110
111 /**
112 * Incorporate entropy into the RNG state then produce output.
113 * Some RNG types implement this using a single operation, default
114 * calls add_entropy + randomize in sequence.
115 *
116 * Use this to further bind the outputs to your current
117 * process/protocol state. For instance if generating a new key
118 * for use in a session, include a session ID or other such
119 * value. See NIST SP 800-90 A, B, C series for more ideas.
120 *
121 * @param output buffer to hold the random output
122 * @param input entropy buffer to incorporate
123 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
124 * @throws Exception if the RNG fails
125 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
126 */
127 void randomize_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
128 this->fill_bytes_with_input(output, input);
129 }
130
131 void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) {
132 this->randomize_with_input(std::span(output, output_len), std::span(input, input_len));
133 }
134
135 /**
136 * This calls `randomize_with_input` using some timestamps as extra input.
137 *
138 * For a stateful RNG using non-random but potentially unique data the
139 * extra input can help protect against problems with fork, VM state
140 * rollback, or other cases where somehow an RNG state is duplicated. If
141 * both of the duplicated RNG states later incorporate a timestamp (and the
142 * timestamps don't themselves repeat), their outputs will diverge.
143 *
144 * @param output buffer to hold the random output
145 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
146 * @throws Exception if the RNG fails
147 * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
148 */
149 void randomize_with_ts_input(std::span<uint8_t> output);
150
151 void randomize_with_ts_input(uint8_t output[], size_t output_len) {
152 this->randomize_with_ts_input(std::span(output, output_len));
153 }
154
155 /**
156 * @return the name of this RNG type
157 */
158 virtual std::string name() const = 0;
159
160 /**
161 * Clear all internally held values of this RNG
162 * @post is_seeded() == false if the RNG has an internal state that can be cleared.
163 */
164 virtual void clear() = 0;
165
166 /**
167 * Check whether this RNG is seeded.
168 * @return true if this RNG was already seeded, false otherwise.
169 */
170 virtual bool is_seeded() const = 0;
171
172 /**
173 * Poll provided sources for up to poll_bits bits of entropy.
174 * Returns estimate of the number of bits collected.
175 * Sets the seeded state to true if enough entropy was added.
176 *
177 * @throws Exception if RNG accepts input but reseeding failed.
178 */
180 return reseed_from_sources(srcs, poll_bits);
181 }
182
183 /**
184 * Reseed by reading specified bits from the RNG
185 *
186 * Sets the seeded state to true if enough entropy was added.
187 *
188 * @throws Exception if RNG accepts input but reseeding failed.
189 */
191 return reseed_from_rng(rng, poll_bits);
192 }
193
194 // Some utility functions built on the interface above:
195
196 /**
197 * Fill a given byte container with @p bytes random bytes
198 *
199 * @todo deprecate this overload (in favor of randomize())
200 *
201 * @param v the container to be filled with @p bytes random bytes
202 * @throws Exception if RNG fails
203 */
204 void random_vec(std::span<uint8_t> v) { this->randomize(v); }
205
206 /**
207 * Resize a given byte container to @p bytes and fill it with random bytes
208 *
209 * @tparam T the desired byte container type (e.g std::vector<uint8_t>)
210 * @param v the container to be filled with @p bytes random bytes
211 * @param bytes number of random bytes to initialize the container with
212 * @throws Exception if RNG or memory allocation fails
213 */
214 template <concepts::resizable_byte_buffer T>
215 void random_vec(T& v, size_t bytes) {
216 v.resize(bytes);
217 random_vec(v);
218 }
219
220 /**
221 * Create some byte container type and fill it with some random @p bytes.
222 *
223 * @tparam T the desired byte container type (e.g std::vector<uint8_t>)
224 * @param bytes number of random bytes to initialize the container with
225 * @return a container of type T with @p bytes random bytes
226 * @throws Exception if RNG or memory allocation fails
227 */
228 template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
229 requires std::default_initializable<T>
230 T random_vec(size_t bytes) {
231 T result;
232 random_vec(result, bytes);
233 return result;
234 }
235
236 /**
237 * Create a std::array of @p bytes random bytes
238 */
239 template <size_t bytes>
240 std::array<uint8_t, bytes> random_array() {
241 std::array<uint8_t, bytes> result{};
242 random_vec(result);
243 return result;
244 }
245
246 /**
247 * Return a random byte
248 * @return random byte
249 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
250 * @throws Exception if the RNG fails
251 */
252 uint8_t next_byte() {
253 uint8_t b = 0;
254 this->fill_bytes_with_input(std::span(&b, 1), {});
255 return b;
256 }
257
258 /**
259 * @return a random byte that is greater than zero
260 * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
261 * @throws Exception if the RNG fails
262 */
264 uint8_t b = this->next_byte();
265 while(b == 0) {
266 b = this->next_byte();
267 }
268 return b;
269 }
270
271 /**
272 * Reseed by reading specified bits from the RNG
273 *
274 * Sets the seeded state to true if enough entropy was added.
275 *
276 * @throws Exception if RNG accepts input but reseeding failed.
277 */
278 virtual void reseed_from_rng(RandomNumberGenerator& rng,
279 size_t poll_bits = RandomNumberGenerator::DefaultPollBits);
280
281#if !defined(BOTAN_IS_BEING_BUILT)
282 /**
283 * Default poll timeout
284 */
285 static constexpr auto DefaultPollTimeout = std::chrono::milliseconds(50);
286
287 /**
288 * Poll provided sources for up to poll_bits bits of entropy.
289 * Returns estimate of the number of bits collected.
290 *
291 * Sets the seeded state to true if enough entropy was added.
292 *
293 * TODO(Botan4) remove this function
294 */
295 BOTAN_DEPRECATED("Use reseed_from_sources")
296 inline size_t reseed(Entropy_Sources& srcs,
297 size_t poll_bits = RandomNumberGenerator::DefaultPollBits,
298 std::chrono::milliseconds /*unused_timeout*/ = DefaultPollTimeout) {
299 return reseed_from(srcs, poll_bits);
300 }
301#endif
302
303 protected:
304 /**
305 * Poll provided sources for up to poll_bits bits of entropy.
306 * Returns estimate of the number of bits collected.
307 * Sets the seeded state to true if enough entropy was added.
308 *
309 * @throws Exception if RNG accepts input but reseeding failed.
310 */
311 virtual size_t reseed_from_sources(Entropy_Sources& srcs,
312 size_t poll_bits = RandomNumberGenerator::DefaultPollBits);
313
314 /**
315 * Generic interface to provide entropy to a concrete implementation and to
316 * fill a given buffer with random output. Both @p output and @p input may
317 * be empty and should be ignored in that case. If both buffers are
318 * non-empty implementations should typically first apply the @p input data
319 * and then generate random data into @p output.
320 *
321 * This method must be implemented by all RandomNumberGenerator sub-classes.
322 *
323 * @param output Byte buffer to write random bytes into. Implementations
324 * should not read from this buffer.
325 * @param input Byte buffer that may contain bytes to be incorporated in
326 * the RNG's internal state. Implementations may choose to
327 * ignore the bytes in this buffer.
328 */
329 virtual void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) = 0;
330};
331
332/**
333* Convenience typedef
334*/
336
337/**
338* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG)
339*/
341 public:
342 void clear() final { /* no way to clear state of hardware RNG */
343 }
344};
345
346/**
347* Null/stub RNG - fails if you try to use it for anything
348* This is not generally useful except for in certain tests
349*/
351 public:
352 bool is_seeded() const override { return false; }
353
354 bool accepts_input() const override { return false; }
355
356 void clear() override {}
357
358 std::string name() const override { return "Null_RNG"; }
359
360 private:
361 void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> /* ignored */) override;
362};
363
364} // namespace Botan
365
366#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:342
bool accepts_input() const override
Definition rng.h:354
void clear() override
Definition rng.h:356
std::string name() const override
Definition rng.h:358
bool is_seeded() const override
Definition rng.h:352
void randomize(std::span< uint8_t > output)
Definition rng.h:75
RandomNumberGenerator & operator=(RandomNumberGenerator &&rng)=default
std::array< uint8_t, bytes > random_array()
Definition rng.h:240
virtual bool accepts_input() const =0
T random_vec(size_t bytes)
Definition rng.h:230
RandomNumberGenerator(RandomNumberGenerator &&rng)=default
virtual ~RandomNumberGenerator()=default
void add_entropy(std::span< const uint8_t > input)
Definition rng.h:98
virtual size_t reseed_from_sources(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.cpp:52
void randomize(uint8_t output[], size_t length)
Definition rng.h:77
uint8_t next_nonzero_byte()
Definition rng.h:263
static constexpr size_t DefaultPollBits
Definition rng.h:50
void random_vec(T &v, size_t bytes)
Definition rng.h:215
RandomNumberGenerator & operator=(const RandomNumberGenerator &rng)=delete
static constexpr size_t DefaultReseedInterval
Definition rng.h:45
static constexpr auto DefaultPollTimeout
Definition rng.h:285
virtual bool is_seeded() const =0
void randomize_with_ts_input(uint8_t output[], size_t output_len)
Definition rng.h:151
void add_entropy(const uint8_t input[], size_t length)
Definition rng.h:100
virtual std::string name() const =0
virtual void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.cpp:64
void randomize_with_ts_input(std::span< uint8_t > output)
Definition rng.cpp:28
void random_vec(std::span< uint8_t > v)
Definition rng.h:204
size_t reseed_from(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.h:179
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:127
RandomNumberGenerator(const RandomNumberGenerator &rng)=delete
void reseed_from(RandomNumberGenerator &rng, size_t poll_bits=RandomNumberGenerator::DefaultPollBits)
Definition rng.h:190
void add_entropy_T(const T &t)
Definition rng.h:107
void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len)
Definition rng.h:131
size_t reseed(Entropy_Sources &srcs, size_t poll_bits=RandomNumberGenerator::DefaultPollBits, std::chrono::milliseconds=DefaultPollTimeout)
Definition rng.h:296
RandomNumberGenerator RNG
Definition rng.h:335