Botan 2.19.1
Crypto and TLS for C&
stateful_rng.cpp
Go to the documentation of this file.
1/*
2* (C) 2016,2020 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/stateful_rng.h>
8#include <botan/internal/os_utils.h>
9#include <botan/loadstor.h>
10
11#if defined(BOTAN_HAS_SYSTEM_RNG)
12 #include <botan/system_rng.h>
13#endif
14
15namespace Botan {
16
18 {
20 m_reseed_counter = 0;
21 m_last_pid = 0;
23 }
24
26 {
28 m_reseed_counter = 0;
29 }
30
32 {
34 return m_reseed_counter > 0;
35 }
36
37void Stateful_RNG::add_entropy(const uint8_t input[], size_t input_len)
38 {
40
41 update(input, input_len);
42
43 if(8*input_len >= security_level())
44 {
45 reset_reseed_counter();
46 }
47 }
48
49void Stateful_RNG::initialize_with(const uint8_t input[], size_t len)
50 {
52
53 clear();
54 add_entropy(input, len);
55 }
56
57void Stateful_RNG::randomize(uint8_t output[], size_t output_len)
58 {
59 randomize_with_input(output, output_len, nullptr, 0);
60 }
61
62void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len)
63 {
64 uint8_t additional_input[20] = { 0 };
65
66 store_le(OS::get_high_resolution_clock(), additional_input);
67
68#if defined(BOTAN_HAS_SYSTEM_RNG)
70 system_rng.randomize(additional_input + 8, sizeof(additional_input) - 8);
71#else
72 store_le(OS::get_system_timestamp_ns(), additional_input + 8);
73 store_le(OS::get_process_id(), additional_input + 16);
74#endif
75
76 randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
77 }
78
79void Stateful_RNG::randomize_with_input(uint8_t output[], size_t output_len,
80 const uint8_t input[], size_t input_len)
81 {
82 if(output_len == 0)
83 return;
84
86
87 const size_t max_per_request = max_number_of_bytes_per_request();
88
89 if(max_per_request == 0) // no limit
90 {
92 this->generate_output(output, output_len, input, input_len);
93 }
94 else
95 {
96 while(output_len > 0)
97 {
98 const size_t this_req = std::min(max_per_request, output_len);
99
100 /*
101 * We split the request into several requests to the underlying DRBG but
102 * pass the input to each invocation. It might be more sensible to only
103 * provide it for the first invocation, however between 2.0 and 2.15
104 * HMAC_DRBG always provided it for all requests so retain that here.
105 */
106
107 reseed_check();
108 this->generate_output(output, this_req, input, input_len);
109
110 output += this_req;
111 output_len -= this_req;
112 }
113 }
114 }
115
117 size_t poll_bits,
118 std::chrono::milliseconds poll_timeout)
119 {
121
122 const size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout);
123
124 if(bits_collected >= security_level())
125 {
126 reset_reseed_counter();
127 }
128
129 return bits_collected;
130 }
131
133 {
135
137
138 if(poll_bits >= security_level())
139 {
140 reset_reseed_counter();
141 }
142 }
143
144void Stateful_RNG::reset_reseed_counter()
145 {
146 // Lock is held whenever this function is called
147 m_reseed_counter = 1;
148 }
149
151 {
152 // Lock is held whenever this function is called
153
154 const uint32_t cur_pid = OS::get_process_id();
155
156 const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid);
157
158 if(is_seeded() == false ||
159 fork_detected ||
160 (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval))
161 {
162 m_reseed_counter = 0;
163 m_last_pid = cur_pid;
164
165 if(m_underlying_rng)
166 {
167 reseed_from_rng(*m_underlying_rng, security_level());
168 }
169
170 if(m_entropy_sources)
171 {
172 reseed(*m_entropy_sources, security_level());
173 }
174
175 if(!is_seeded())
176 {
177 if(fork_detected)
178 throw Invalid_State("Detected use of fork but cannot reseed DRBG");
179 else
180 throw PRNG_Unseeded(name());
181 }
182 }
183 else
184 {
185 BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded");
186 m_reseed_counter += 1;
187 }
188 }
189
190}
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
virtual void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS)
Definition: rng.cpp:59
virtual void randomize(uint8_t output[], size_t length)=0
virtual std::string name() const =0
virtual size_t reseed(Entropy_Sources &srcs, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS, std::chrono::milliseconds poll_timeout=BOTAN_RNG_RESEED_DEFAULT_TIMEOUT)
Definition: rng.cpp:45
void randomize_with_ts_input(uint8_t output[], size_t output_len) override final
virtual void generate_output(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len)=0
virtual size_t security_level() const =0
virtual void clear_state()=0
size_t reseed(Entropy_Sources &srcs, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS, std::chrono::milliseconds poll_timeout=BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override
void initialize_with(const uint8_t input[], size_t length)
virtual void update(const uint8_t input[], size_t input_len)=0
bool is_seeded() const override final
void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) override final
virtual size_t max_number_of_bytes_per_request() const =0
void clear() override final
void randomize(uint8_t output[], size_t output_len) override final
void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS) override final
void add_entropy(const uint8_t input[], size_t input_len) override final
uint64_t BOTAN_TEST_API get_high_resolution_clock()
Definition: os_utils.cpp:241
uint64_t BOTAN_TEST_API get_system_timestamp_ns()
Definition: os_utils.cpp:293
uint32_t BOTAN_TEST_API get_process_id()
Definition: os_utils.cpp:96
Definition: alg_id.cpp:13
RandomNumberGenerator & system_rng()
Definition: system_rng.cpp:283
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:454