Coverage Report

Created: 2021-01-13 07:05

/src/botan/src/lib/rng/stateful_rng/stateful_rng.cpp
Line
Count
Source (jump to first uncovered line)
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/internal/loadstor.h>
10
11
#if defined(BOTAN_HAS_SYSTEM_RNG)
12
  #include <botan/system_rng.h>
13
#endif
14
15
namespace Botan {
16
17
void Stateful_RNG::clear()
18
7
   {
19
7
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
20
7
   m_reseed_counter = 0;
21
7
   m_last_pid = 0;
22
7
   clear_state();
23
7
   }
24
25
void Stateful_RNG::force_reseed()
26
0
   {
27
0
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
28
0
   m_reseed_counter = 0;
29
0
   }
30
31
bool Stateful_RNG::is_seeded() const
32
554k
   {
33
554k
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
34
554k
   return m_reseed_counter > 0;
35
554k
   }
36
37
void Stateful_RNG::add_entropy(const uint8_t input[], size_t input_len)
38
7
   {
39
7
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
40
41
7
   update(input, input_len);
42
43
7
   if(8*input_len >= security_level())
44
7
      {
45
7
      reset_reseed_counter();
46
7
      }
47
7
   }
48
49
void Stateful_RNG::initialize_with(const uint8_t input[], size_t len)
50
0
   {
51
0
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
52
53
0
   clear();
54
0
   add_entropy(input, len);
55
0
   }
56
57
void Stateful_RNG::randomize(uint8_t output[], size_t output_len)
58
473k
   {
59
473k
   randomize_with_input(output, output_len, nullptr, 0);
60
473k
   }
61
62
void Stateful_RNG::randomize_with_ts_input(uint8_t output[], size_t output_len)
63
0
   {
64
0
   uint8_t additional_input[20] = { 0 };
65
66
0
   store_le(OS::get_high_resolution_clock(), additional_input);
67
68
0
#if defined(BOTAN_HAS_SYSTEM_RNG)
69
0
   System_RNG system_rng;
70
0
   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
0
   randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
77
0
   }
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
473k
   {
82
473k
   if(output_len == 0)
83
0
      return;
84
85
473k
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
86
87
473k
   const size_t max_per_request = max_number_of_bytes_per_request();
88
89
473k
   if(max_per_request == 0) // no limit
90
473k
      {
91
473k
      reseed_check();
92
473k
      this->generate_output(output, output_len, input, input_len);
93
473k
      }
94
0
   else
95
0
      {
96
0
      while(output_len > 0)
97
0
         {
98
0
         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
0
         reseed_check();
108
0
         this->generate_output(output, this_req, input, input_len);
109
110
0
         output += this_req;
111
0
         output_len -= this_req;
112
0
         }
113
0
      }
114
473k
   }
115
116
size_t Stateful_RNG::reseed(Entropy_Sources& srcs,
117
                            size_t poll_bits,
118
                            std::chrono::milliseconds poll_timeout)
119
0
   {
120
0
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
121
122
0
   const size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout);
123
124
0
   if(bits_collected >= security_level())
125
0
      {
126
0
      reset_reseed_counter();
127
0
      }
128
129
0
   return bits_collected;
130
0
   }
131
132
void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
133
0
   {
134
0
   lock_guard_type<recursive_mutex_type> lock(m_mutex);
135
136
0
   RandomNumberGenerator::reseed_from_rng(rng, poll_bits);
137
138
0
   if(poll_bits >= security_level())
139
0
      {
140
0
      reset_reseed_counter();
141
0
      }
142
0
   }
143
144
void Stateful_RNG::reset_reseed_counter()
145
7
   {
146
   // Lock is held whenever this function is called
147
7
   m_reseed_counter = 1;
148
7
   }
149
150
void Stateful_RNG::reseed_check()
151
473k
   {
152
   // Lock is held whenever this function is called
153
154
473k
   const uint32_t cur_pid = OS::get_process_id();
155
156
473k
   const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid);
157
158
473k
   if(is_seeded() == false ||
159
473k
      fork_detected ||
160
473k
      (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval))
161
0
      {
162
0
      m_reseed_counter = 0;
163
0
      m_last_pid = cur_pid;
164
165
0
      if(m_underlying_rng)
166
0
         {
167
0
         reseed_from_rng(*m_underlying_rng, security_level());
168
0
         }
169
170
0
      if(m_entropy_sources)
171
0
         {
172
0
         reseed(*m_entropy_sources, security_level());
173
0
         }
174
175
0
      if(!is_seeded())
176
0
         {
177
0
         if(fork_detected)
178
0
            throw Invalid_State("Detected use of fork but cannot reseed DRBG");
179
0
         else
180
0
            throw PRNG_Unseeded(name());
181
473k
         }
182
473k
      }
183
473k
   else
184
473k
      {
185
473k
      BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded");
186
473k
      m_reseed_counter += 1;
187
473k
      }
188
473k
   }
189
190
}