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