Coverage Report

Created: 2020-05-23 13:54

/src/botan/src/lib/rng/hmac_drbg/hmac_drbg.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* HMAC_DRBG
3
* (C) 2014,2015,2016 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/hmac_drbg.h>
9
#include <algorithm>
10
11
namespace Botan {
12
13
namespace {
14
15
void check_limits(size_t reseed_interval,
16
                  size_t max_number_of_bytes_per_request)
17
0
   {
18
0
   // SP800-90A permits up to 2^48, but it is not usable on 32 bit
19
0
   // platforms, so we only allow up to 2^24, which is still reasonably high
20
0
   if(reseed_interval == 0 || reseed_interval > static_cast<size_t>(1) << 24)
21
0
      {
22
0
      throw Invalid_Argument("Invalid value for reseed_interval");
23
0
      }
24
0
25
0
   if(max_number_of_bytes_per_request == 0 || max_number_of_bytes_per_request > 64 * 1024)
26
0
      {
27
0
      throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request");
28
0
      }
29
0
   }
30
31
}
32
33
HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
34
                     RandomNumberGenerator& underlying_rng,
35
                     size_t reseed_interval,
36
                     size_t max_number_of_bytes_per_request) :
37
   Stateful_RNG(underlying_rng, reseed_interval),
38
   m_mac(std::move(prf)),
39
   m_max_number_of_bytes_per_request(max_number_of_bytes_per_request)
40
0
   {
41
0
   BOTAN_ASSERT_NONNULL(m_mac);
42
0
43
0
   check_limits(reseed_interval, max_number_of_bytes_per_request);
44
0
45
0
   clear();
46
0
   }
47
48
HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
49
                     RandomNumberGenerator& underlying_rng,
50
                     Entropy_Sources& entropy_sources,
51
                     size_t reseed_interval,
52
                     size_t max_number_of_bytes_per_request) :
53
   Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
54
   m_mac(std::move(prf)),
55
   m_max_number_of_bytes_per_request(max_number_of_bytes_per_request)
56
0
   {
57
0
   BOTAN_ASSERT_NONNULL(m_mac);
58
0
59
0
   check_limits(reseed_interval, max_number_of_bytes_per_request);
60
0
61
0
   clear();
62
0
   }
63
64
HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
65
                     Entropy_Sources& entropy_sources,
66
                     size_t reseed_interval,
67
                     size_t max_number_of_bytes_per_request) :
68
   Stateful_RNG(entropy_sources, reseed_interval),
69
   m_mac(std::move(prf)),
70
   m_max_number_of_bytes_per_request(max_number_of_bytes_per_request)
71
0
   {
72
0
   BOTAN_ASSERT_NONNULL(m_mac);
73
0
74
0
   check_limits(reseed_interval, max_number_of_bytes_per_request);
75
0
76
0
   clear();
77
0
   }
78
79
HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) :
80
   Stateful_RNG(),
81
   m_mac(std::move(prf)),
82
   m_max_number_of_bytes_per_request(64*1024)
83
0
   {
84
0
   BOTAN_ASSERT_NONNULL(m_mac);
85
0
   clear();
86
0
   }
87
88
void HMAC_DRBG::clear()
89
0
   {
90
0
   Stateful_RNG::clear();
91
0
92
0
   const size_t output_length = m_mac->output_length();
93
0
94
0
   m_V.resize(output_length);
95
0
   for(size_t i = 0; i != m_V.size(); ++i)
96
0
      m_V[i] = 0x01;
97
0
   m_mac->set_key(std::vector<uint8_t>(output_length, 0x00));
98
0
   }
99
100
std::string HMAC_DRBG::name() const
101
0
   {
102
0
   return "HMAC_DRBG(" + m_mac->name() + ")";
103
0
   }
104
105
void HMAC_DRBG::randomize(uint8_t output[], size_t output_len)
106
0
   {
107
0
   randomize_with_input(output, output_len, nullptr, 0);
108
0
   }
109
110
/*
111
* HMAC_DRBG generation
112
* See NIST SP800-90A section 10.1.2.5
113
*/
114
void HMAC_DRBG::randomize_with_input(uint8_t output[], size_t output_len,
115
                                     const uint8_t input[], size_t input_len)
116
0
   {
117
0
   while(output_len > 0)
118
0
      {
119
0
      size_t this_req = std::min(m_max_number_of_bytes_per_request, output_len);
120
0
      output_len -= this_req;
121
0
122
0
      reseed_check();
123
0
124
0
      if(input_len > 0)
125
0
         {
126
0
         update(input, input_len);
127
0
         }
128
0
129
0
      while(this_req)
130
0
         {
131
0
         const size_t to_copy = std::min(this_req, m_V.size());
132
0
         m_mac->update(m_V.data(), m_V.size());
133
0
         m_mac->final(m_V.data());
134
0
         copy_mem(output, m_V.data(), to_copy);
135
0
136
0
         output += to_copy;
137
0
         this_req -= to_copy;
138
0
         }
139
0
140
0
      update(input, input_len);
141
0
      }
142
0
143
0
   }
144
145
/*
146
* Reset V and the mac key with new values
147
* See NIST SP800-90A section 10.1.2.2
148
*/
149
void HMAC_DRBG::update(const uint8_t input[], size_t input_len)
150
0
   {
151
0
   secure_vector<uint8_t> T(m_V.size());
152
0
   m_mac->update(m_V);
153
0
   m_mac->update(0x00);
154
0
   m_mac->update(input, input_len);
155
0
   m_mac->final(T.data());
156
0
   m_mac->set_key(T);
157
0
158
0
   m_mac->update(m_V.data(), m_V.size());
159
0
   m_mac->final(m_V.data());
160
0
161
0
   if(input_len > 0)
162
0
      {
163
0
      m_mac->update(m_V);
164
0
      m_mac->update(0x01);
165
0
      m_mac->update(input, input_len);
166
0
      m_mac->final(T.data());
167
0
      m_mac->set_key(T);
168
0
169
0
      m_mac->update(m_V.data(), m_V.size());
170
0
      m_mac->final(m_V.data());
171
0
      }
172
0
   }
173
174
void HMAC_DRBG::add_entropy(const uint8_t input[], size_t input_len)
175
0
   {
176
0
   update(input, input_len);
177
0
178
0
   if(8*input_len >= security_level())
179
0
      {
180
0
      reset_reseed_counter();
181
0
      }
182
0
   }
183
184
size_t HMAC_DRBG::security_level() const
185
0
   {
186
0
   // security strength of the hash function
187
0
   // for pre-image resistance (see NIST SP 800-57)
188
0
   // SHA-160: 128 bits, SHA-224, SHA-512/224: 192 bits,
189
0
   // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits
190
0
   // NIST SP 800-90A only supports up to 256 bits though
191
0
192
0
   const size_t output_length = m_mac->output_length();
193
0
194
0
   if(output_length < 32)
195
0
      {
196
0
      return (output_length - 4) * 8;
197
0
      }
198
0
   else
199
0
      {
200
0
      return 32 * 8;
201
0
      }
202
0
   }
203
}