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