Coverage Report

Created: 2024-06-28 06:39

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