Botan  2.19.1
Crypto and TLS for C++11
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 
15 namespace Botan {
16 
18  {
20  m_reseed_counter = 0;
21  m_last_pid = 0;
22  clear_state();
23  }
24 
26  {
28  m_reseed_counter = 0;
29  }
30 
32  {
34  return m_reseed_counter > 0;
35  }
36 
37 void 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 
49 void Stateful_RNG::initialize_with(const uint8_t input[], size_t len)
50  {
52 
53  clear();
54  add_entropy(input, len);
55  }
56 
57 void Stateful_RNG::randomize(uint8_t output[], size_t output_len)
58  {
59  randomize_with_input(output, output_len, nullptr, 0);
60  }
61 
62 void 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 
79 void 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  {
91  reseed_check();
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 
144 void 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 }
void randomize_with_ts_input(uint8_t output[], size_t output_len) overridefinal
RandomNumberGenerator & system_rng()
Definition: system_rng.cpp:283
virtual void clear_state()=0
uint32_t BOTAN_TEST_API get_process_id()
Definition: os_utils.cpp:96
virtual size_t security_level() const =0
void add_entropy(const uint8_t input[], size_t input_len) overridefinal
virtual void generate_output(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len)=0
void randomize_with_input(uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len) overridefinal
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS) overridefinal
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
virtual std::string name() const =0
uint64_t BOTAN_TEST_API get_system_timestamp_ns()
Definition: os_utils.cpp:293
bool is_seeded() const overridefinal
virtual size_t max_number_of_bytes_per_request() const =0
Definition: alg_id.cpp:13
void randomize(uint8_t output[], size_t output_len) overridefinal
virtual void reseed_from_rng(RandomNumberGenerator &rng, size_t poll_bits=BOTAN_RNG_RESEED_POLL_BITS)
Definition: rng.cpp:59
void initialize_with(const uint8_t input[], size_t length)
virtual void update(const uint8_t input[], size_t input_len)=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 randomize(uint8_t out[], size_t len) override
Definition: system_rng.h:30
void clear() overridefinal
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:454
uint64_t BOTAN_TEST_API get_high_resolution_clock()
Definition: os_utils.cpp:241