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