Coverage Report

Created: 2022-06-23 06:44

/src/botan/build/include/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
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H_
9
#define BOTAN_RANDOM_NUMBER_GENERATOR_H_
10
11
#include <botan/secmem.h>
12
#include <botan/exceptn.h>
13
#include <botan/mutex.h>
14
#include <type_traits>
15
#include <chrono>
16
#include <string>
17
18
namespace Botan {
19
20
class Entropy_Sources;
21
22
/**
23
* An interface to a cryptographic random number generator
24
*/
25
class BOTAN_PUBLIC_API(2,0) RandomNumberGenerator
26
   {
27
   public:
28
332
      virtual ~RandomNumberGenerator() = default;
29
30
332
      RandomNumberGenerator() = default;
31
32
      /*
33
      * Never copy a RNG, create a new one
34
      */
35
      RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
36
      RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
37
38
      /**
39
      * Randomize a byte array.
40
      *
41
      * May block shortly if e.g. the RNG is not yet initialized
42
      * or a retry because of insufficient entropy is needed.
43
      *
44
      * @param output the byte array to hold the random output.
45
      * @param length the length of the byte array output in bytes.
46
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
47
      * @throws Exception if the RNG fails
48
      */
49
      virtual void randomize(uint8_t output[], size_t length) = 0;
50
51
      /**
52
      * Returns false if it is known that this RNG object is not able to accept
53
      * externally provided inputs (via add_entropy, randomize_with_input, etc).
54
      * In this case, any such provided inputs are ignored.
55
      *
56
      * If this function returns true, then inputs may or may not be accepted.
57
      */
58
      virtual bool accepts_input() const = 0;
59
60
      /**
61
      * Incorporate some additional data into the RNG state. For
62
      * example adding nonces or timestamps from a peer's protocol
63
      * message can help hedge against VM state rollback attacks.
64
      * A few RNG types do not accept any externally provided input,
65
      * in which case this function is a no-op.
66
      *
67
      * @param input a byte array containg the entropy to be added
68
      * @param length the length of the byte array in
69
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
70
      */
71
      virtual void add_entropy(const uint8_t input[], size_t length) = 0;
72
73
      /**
74
      * Incorporate some additional data into the RNG state.
75
      */
76
      template<typename T> void add_entropy_T(const T& t)
77
         {
78
         static_assert(std::is_standard_layout<T>::value && std::is_trivial<T>::value, "add_entropy_T data must be POD");
79
         this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
80
         }
81
82
      /**
83
      * Incorporate entropy into the RNG state then produce output.
84
      * Some RNG types implement this using a single operation, default
85
      * calls add_entropy + randomize in sequence.
86
      *
87
      * Use this to further bind the outputs to your current
88
      * process/protocol state. For instance if generating a new key
89
      * for use in a session, include a session ID or other such
90
      * value. See NIST SP 800-90 A, B, C series for more ideas.
91
      *
92
      * @param output buffer to hold the random output
93
      * @param output_len size of the output buffer in bytes
94
      * @param input entropy buffer to incorporate
95
      * @param input_len size of the input buffer in bytes
96
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
97
      * @throws Exception if the RNG fails
98
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
99
      */
100
      virtual void randomize_with_input(uint8_t output[], size_t output_len,
101
                                        const uint8_t input[], size_t input_len);
102
103
      /**
104
      * This calls `randomize_with_input` using some timestamps as extra input.
105
      *
106
      * For a stateful RNG using non-random but potentially unique data the
107
      * extra input can help protect against problems with fork, VM state
108
      * rollback, or other cases where somehow an RNG state is duplicated. If
109
      * both of the duplicated RNG states later incorporate a timestamp (and the
110
      * timestamps don't themselves repeat), their outputs will diverge.
111
      *
112
      * @param output buffer to hold the random output
113
      * @param output_len size of the output buffer in bytes
114
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
115
      * @throws Exception if the RNG fails
116
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
117
      */
118
      virtual void randomize_with_ts_input(uint8_t output[], size_t output_len);
119
120
      /**
121
      * @return the name of this RNG type
122
      */
123
      virtual std::string name() const = 0;
124
125
      /**
126
      * Clear all internally held values of this RNG
127
      * @post is_seeded() == false if the RNG has an internal state that can be cleared.
128
      */
129
      virtual void clear() = 0;
130
131
      /**
132
      * Check whether this RNG is seeded.
133
      * @return true if this RNG was already seeded, false otherwise.
134
      */
135
      virtual bool is_seeded() const = 0;
136
137
      /**
138
      * Poll provided sources for up to poll_bits bits of entropy
139
      * or until the timeout expires. Returns estimate of the number
140
      * of bits collected.
141
      *
142
      * Sets the seeded state to true if enough entropy was added.
143
      */
144
      virtual size_t reseed(Entropy_Sources& srcs,
145
                            size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
146
                            std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
147
148
      /**
149
      * Reseed by reading specified bits from the RNG
150
      *
151
      * Sets the seeded state to true if enough entropy was added.
152
      *
153
      * @throws Exception if RNG accepts input but reseeding failed.
154
      */
155
      virtual void reseed_from_rng(RandomNumberGenerator& rng,
156
                                   size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS);
157
158
      // Some utility functions built on the interface above:
159
160
      /**
161
      * Return a random vector
162
      * @param bytes number of bytes in the result
163
      * @return randomized vector of length bytes
164
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
165
      * @throws Exception if the RNG fails
166
      */
167
      secure_vector<uint8_t> random_vec(size_t bytes)
168
551k
         {
169
551k
         secure_vector<uint8_t> output;
170
551k
         random_vec(output, bytes);
171
551k
         return output;
172
551k
         }
173
174
      template<typename Alloc>
175
         void random_vec(std::vector<uint8_t, Alloc>& v, size_t bytes)
176
557k
         {
177
557k
         v.resize(bytes);
178
557k
         this->randomize(v.data(), v.size());
179
557k
         }
void Botan::RandomNumberGenerator::random_vec<Botan::secure_allocator<unsigned char> >(std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> >&, unsigned long)
Line
Count
Source
176
557k
         {
177
557k
         v.resize(bytes);
178
557k
         this->randomize(v.data(), v.size());
179
557k
         }
void Botan::RandomNumberGenerator::random_vec<std::__1::allocator<unsigned char> >(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long)
Line
Count
Source
176
362
         {
177
362
         v.resize(bytes);
178
362
         this->randomize(v.data(), v.size());
179
362
         }
180
181
      /**
182
      * Return a random byte
183
      * @return random byte
184
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
185
      * @throws Exception if the RNG fails
186
      */
187
      uint8_t next_byte()
188
0
         {
189
0
         uint8_t b;
190
0
         this->randomize(&b, 1);
191
0
         return b;
192
0
         }
193
194
      /**
195
      * @return a random byte that is greater than zero
196
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
197
      * @throws Exception if the RNG fails
198
      */
199
      uint8_t next_nonzero_byte()
200
0
         {
201
0
         uint8_t b = this->next_byte();
202
0
         while(b == 0)
203
0
            b = this->next_byte();
204
0
         return b;
205
0
         }
206
   };
207
208
/**
209
* Convenience typedef
210
*/
211
typedef RandomNumberGenerator RNG;
212
213
/**
214
* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG)
215
*/
216
class BOTAN_PUBLIC_API(2,0) Hardware_RNG : public RandomNumberGenerator
217
   {
218
   public:
219
0
      virtual void clear() final override { /* no way to clear state of hardware RNG */ }
220
   };
221
222
/**
223
* Null/stub RNG - fails if you try to use it for anything
224
* This is not generally useful except for in certain tests
225
*/
226
class BOTAN_PUBLIC_API(2,0) Null_RNG final : public RandomNumberGenerator
227
   {
228
   public:
229
0
      bool is_seeded() const override { return false; }
230
231
0
      bool accepts_input() const override { return false; }
232
233
0
      void clear() override {}
234
235
      void randomize(uint8_t[], size_t) override
236
0
         {
237
0
         throw PRNG_Unseeded("Null_RNG called");
238
0
         }
239
240
0
      void add_entropy(const uint8_t[], size_t) override {}
241
242
0
      std::string name() const override { return "Null_RNG"; }
243
   };
244
245
#if defined(BOTAN_TARGET_OS_HAS_THREADS)
246
/**
247
* Wraps access to a RNG in a mutex
248
* Note that most of the time it's much better to use a RNG per thread
249
* otherwise the RNG will act as an unnecessary contention point
250
*
251
* Since 2.16.0 all Stateful_RNG instances have an internal lock, so
252
* this class is no longer needed. It will be removed in a future major
253
* release.
254
*/
255
class BOTAN_PUBLIC_API(2,0) Serialized_RNG final : public RandomNumberGenerator
256
   {
257
   public:
258
      void randomize(uint8_t out[], size_t len) override
259
0
         {
260
0
         lock_guard_type<mutex_type> lock(m_mutex);
261
0
         m_rng->randomize(out, len);
262
0
         }
263
264
      bool accepts_input() const override
265
0
         {
266
0
         lock_guard_type<mutex_type> lock(m_mutex);
267
0
         return m_rng->accepts_input();
268
0
         }
269
270
      bool is_seeded() const override
271
0
         {
272
0
         lock_guard_type<mutex_type> lock(m_mutex);
273
0
         return m_rng->is_seeded();
274
0
         }
275
276
      void clear() override
277
0
         {
278
0
         lock_guard_type<mutex_type> lock(m_mutex);
279
0
         m_rng->clear();
280
0
         }
281
282
      std::string name() const override
283
0
         {
284
0
         lock_guard_type<mutex_type> lock(m_mutex);
285
0
         return m_rng->name();
286
0
         }
287
288
      size_t reseed(Entropy_Sources& src,
289
                    size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
290
                    std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override
291
0
         {
292
0
         lock_guard_type<mutex_type> lock(m_mutex);
293
0
         return m_rng->reseed(src, poll_bits, poll_timeout);
294
0
         }
295
296
      void add_entropy(const uint8_t in[], size_t len) override
297
0
         {
298
0
         lock_guard_type<mutex_type> lock(m_mutex);
299
0
         m_rng->add_entropy(in, len);
300
0
         }
301
302
      /**
303
      * Since 2.16.0 this is no longer needed for any RNG type. This
304
      * class will be removed in a future major release.
305
      */
306
      BOTAN_DEPRECATED("Use version accepting a unique_ptr")
307
0
      explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {}
308
309
      /**
310
      * Since 2.16.0 this is no longer needed for any RNG type. This
311
      * class will be removed in a future major release.
312
      */
313
0
      explicit Serialized_RNG(std::unique_ptr<RandomNumberGenerator> rng) : m_rng(std::move(rng)) {}
314
315
   private:
316
      mutable mutex_type m_mutex;
317
      std::unique_ptr<RandomNumberGenerator> m_rng;
318
   };
319
#endif
320
321
}
322
323
#endif