• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13215274653

08 Feb 2025 11:38AM UTC coverage: 91.655% (-0.009%) from 91.664%
13215274653

Pull #4650

github

web-flow
Merge 107f31833 into bc555cd3c
Pull Request #4650: Reorganize code and reduce header dependencies

94836 of 103471 relevant lines covered (91.65%)

11230958.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.37
/src/lib/rng/rng.h
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

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
      /**
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;
4,679✔
49

50
      RandomNumberGenerator() = default;
11,889✔
51

52
      /*
53
      * Never copy a RNG, create a new one
54
      */
55
      RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
56
      RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
57

58
      /**
59
      * Randomize a byte array.
60
      *
61
      * May block shortly if e.g. the RNG is not yet initialized
62
      * or a retry because of insufficient entropy is needed.
63
      *
64
      * @param output the byte array to hold the random output.
65
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
66
      * @throws Exception if the RNG fails
67
      */
68
      void randomize(std::span<uint8_t> output) { this->fill_bytes_with_input(output, {}); }
1,895,695✔
69

70
      void randomize(uint8_t output[], size_t length) { this->randomize(std::span(output, length)); }
497,252✔
71

72
      /**
73
      * Returns false if it is known that this RNG object is not able to accept
74
      * externally provided inputs (via add_entropy, randomize_with_input, etc).
75
      * In this case, any such provided inputs are ignored.
76
      *
77
      * If this function returns true, then inputs may or may not be accepted.
78
      */
79
      virtual bool accepts_input() const = 0;
80

81
      /**
82
      * Incorporate some additional data into the RNG state. For
83
      * example adding nonces or timestamps from a peer's protocol
84
      * message can help hedge against VM state rollback attacks.
85
      * A few RNG types do not accept any externally provided input,
86
      * in which case this function is a no-op.
87
      *
88
      * @param input a byte array containing the entropy to be added
89
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
90
      */
91
      void add_entropy(std::span<const uint8_t> input) { this->fill_bytes_with_input({}, input); }
23,034✔
92

93
      void add_entropy(const uint8_t input[], size_t length) { this->add_entropy(std::span(input, length)); }
14,069✔
94

95
      /**
96
      * Incorporate some additional data into the RNG state.
97
      */
98
      template <typename T>
99
         requires std::is_standard_layout<T>::value && std::is_trivial<T>::value
100
      void add_entropy_T(const T& t) {
101
         this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
102
      }
103

104
      /**
105
      * Incorporate entropy into the RNG state then produce output.
106
      * Some RNG types implement this using a single operation, default
107
      * calls add_entropy + randomize in sequence.
108
      *
109
      * Use this to further bind the outputs to your current
110
      * process/protocol state. For instance if generating a new key
111
      * for use in a session, include a session ID or other such
112
      * value. See NIST SP 800-90 A, B, C series for more ideas.
113
      *
114
      * @param output buffer to hold the random output
115
      * @param input entropy buffer to incorporate
116
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
117
      * @throws Exception if the RNG fails
118
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
119
      */
120
      void randomize_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) {
20,433✔
121
         this->fill_bytes_with_input(output, input);
18,972✔
122
      }
4✔
123

124
      void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) {
1,461✔
125
         this->randomize_with_input(std::span(output, output_len), std::span(input, input_len));
1,461✔
126
      }
127

128
      /**
129
      * This calls `randomize_with_input` using some timestamps as extra input.
130
      *
131
      * For a stateful RNG using non-random but potentially unique data the
132
      * extra input can help protect against problems with fork, VM state
133
      * rollback, or other cases where somehow an RNG state is duplicated. If
134
      * both of the duplicated RNG states later incorporate a timestamp (and the
135
      * timestamps don't themselves repeat), their outputs will diverge.
136
      *
137
      * @param output buffer to hold the random output
138
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
139
      * @throws Exception if the RNG fails
140
      * @throws Exception may throw if the RNG accepts input, but adding the entropy failed.
141
      */
142
      void randomize_with_ts_input(std::span<uint8_t> output);
143

144
      void randomize_with_ts_input(uint8_t output[], size_t output_len) {
2✔
145
         this->randomize_with_ts_input(std::span(output, output_len));
2✔
146
      }
147

148
      /**
149
      * @return the name of this RNG type
150
      */
151
      virtual std::string name() const = 0;
152

153
      /**
154
      * Clear all internally held values of this RNG
155
      * @post is_seeded() == false if the RNG has an internal state that can be cleared.
156
      */
157
      virtual void clear() = 0;
158

159
      /**
160
      * Check whether this RNG is seeded.
161
      * @return true if this RNG was already seeded, false otherwise.
162
      */
163
      virtual bool is_seeded() const = 0;
164

165
      /**
166
      * Poll provided sources for up to poll_bits bits of entropy
167
      * or until the timeout expires. Returns estimate of the number
168
      * of bits collected.
169
      *
170
      * Sets the seeded state to true if enough entropy was added.
171
      */
172
      virtual size_t reseed(Entropy_Sources& srcs,
173
                            size_t poll_bits = RandomNumberGenerator::DefaultPollBits,
174
                            std::chrono::milliseconds poll_timeout = RandomNumberGenerator::DefaultPollTimeout);
175

176
      /**
177
      * Reseed by reading specified bits from the RNG
178
      *
179
      * Sets the seeded state to true if enough entropy was added.
180
      *
181
      * @throws Exception if RNG accepts input but reseeding failed.
182
      */
183
      virtual void reseed_from_rng(RandomNumberGenerator& rng,
184
                                   size_t poll_bits = RandomNumberGenerator::DefaultPollBits);
185

186
      // Some utility functions built on the interface above:
187

188
      /**
189
      * Fill a given byte container with @p bytes random bytes
190
      *
191
      * @todo deprecate this overload (in favor of randomize())
192
      *
193
      * @param  v     the container to be filled with @p bytes random bytes
194
      * @throws Exception if RNG fails
195
      */
196
      void random_vec(std::span<uint8_t> v) { this->randomize(v); }
1,360,887✔
197

198
      /**
199
      * Resize a given byte container to @p bytes and fill it with random bytes
200
      *
201
      * @tparam T     the desired byte container type (e.g std::vector<uint8_t>)
202
      * @param  v     the container to be filled with @p bytes random bytes
203
      * @param  bytes number of random bytes to initialize the container with
204
      * @throws Exception if RNG or memory allocation fails
205
      */
206
      template <concepts::resizable_byte_buffer T>
207
      void random_vec(T& v, size_t bytes) {
677,416✔
208
         v.resize(bytes);
677,416✔
209
         random_vec(v);
677,416✔
210
      }
677,384✔
211

212
      /**
213
      * Create some byte container type and fill it with some random @p bytes.
214
      *
215
      * @tparam T     the desired byte container type (e.g std::vector<uint8_t>)
216
      * @param  bytes number of random bytes to initialize the container with
217
      * @return       a container of type T with @p bytes random bytes
218
      * @throws Exception if RNG or memory allocation fails
219
      */
220
      template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
221
         requires std::default_initializable<T>
222
      T random_vec(size_t bytes) {
674,014✔
223
         T result;
674,014✔
224
         random_vec(result, bytes);
674,014✔
225
         return result;
673,982✔
226
      }
32✔
227

228
      /**
229
       * Create a std::array of @p bytes random bytes
230
       */
231
      template <size_t bytes>
232
      std::array<uint8_t, bytes> random_array() {
8,109✔
233
         std::array<uint8_t, bytes> result;
234
         random_vec(result);
8,109✔
235
         return result;
8,109✔
236
      }
237

238
      /**
239
      * Return a random byte
240
      * @return random byte
241
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
242
      * @throws Exception if the RNG fails
243
      */
244
      uint8_t next_byte() {
9,006,179✔
245
         uint8_t b;
9,004,925✔
246
         this->fill_bytes_with_input(std::span(&b, 1), {});
8,932,475✔
247
         return b;
8,922,934✔
248
      }
249

250
      /**
251
      * @return a random byte that is greater than zero
252
      * @throws PRNG_Unseeded if the RNG fails because it has not enough entropy
253
      * @throws Exception if the RNG fails
254
      */
255
      uint8_t next_nonzero_byte() {
91,198✔
256
         uint8_t b = this->next_byte();
91,198✔
257
         while(b == 0) {
91,526✔
258
            b = this->next_byte();
328✔
259
         }
260
         return b;
91,198✔
261
      }
262

263
   protected:
264
      /**
265
      * Generic interface to provide entropy to a concrete implementation and to
266
      * fill a given buffer with random output. Both @p output and @p input may
267
      * be empty and should be ignored in that case. If both buffers are
268
      * non-empty implementations should typically first apply the @p input data
269
      * and then generate random data into @p output.
270
      *
271
      * This method must be implemented by all RandomNumberGenerator sub-classes.
272
      *
273
      * @param output  Byte buffer to write random bytes into. Implementations
274
      *                should not read from this buffer.
275
      * @param input   Byte buffer that may contain bytes to be incorporated in
276
      *                the RNG's internal state. Implementations may choose to
277
      *                ignore the bytes in this buffer.
278
      */
279
      virtual void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) = 0;
280
};
281

282
/**
283
* Convenience typedef
284
*/
285
typedef RandomNumberGenerator RNG;
286

287
/**
288
* Hardware_RNG exists to tag hardware RNG types (PKCS11_RNG, TPM_RNG, Processor_RNG)
289
*/
290
class BOTAN_PUBLIC_API(2, 0) Hardware_RNG : public RandomNumberGenerator {
24✔
291
   public:
292
      void clear() final { /* no way to clear state of hardware RNG */
×
293
      }
×
294
};
295

296
/**
297
* Null/stub RNG - fails if you try to use it for anything
298
* This is not generally useful except for in certain tests
299
*/
300
class BOTAN_PUBLIC_API(2, 0) Null_RNG final : public RandomNumberGenerator {
7,387✔
301
   public:
302
      bool is_seeded() const override { return false; }
1,321✔
303

304
      bool accepts_input() const override { return false; }
×
305

306
      void clear() override {}
×
307

308
      std::string name() const override { return "Null_RNG"; }
×
309

310
   private:
311
      void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> /* ignored */) override;
312
};
313

314
}  // namespace Botan
315

316
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc