Botan 3.11.0
Crypto and TLS for C&
hmac_drbg.cpp
Go to the documentation of this file.
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
10#include <botan/exceptn.h>
11#include <botan/mac.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/fmt.h>
14#include <algorithm>
15
16namespace Botan {
17
18namespace {
19
20size_t hmac_drbg_security_level(size_t mac_output_length) {
21 // security strength of the hash function
22 // for pre-image resistance (see NIST SP 800-57)
23 // SHA-1: 128 bits
24 // SHA-224, SHA-512/224: 192 bits,
25 // SHA-256, SHA-512/256, SHA-384, SHA-512: >= 256 bits
26 // NIST SP 800-90A only supports up to 256 bits though
27
28 if(mac_output_length < 32) {
29 return (mac_output_length - 4) * 8;
30 } else {
31 return 32 * 8;
32 }
33}
34
35void check_limits(size_t reseed_interval, size_t max_number_of_bytes_per_request) {
36 // SP800-90A permits up to 2^48, but it is not usable on 32 bit
37 // platforms, so we only allow up to 2^24, which is still reasonably high
38 if(reseed_interval == 0 || reseed_interval > static_cast<size_t>(1) << 24) {
39 throw Invalid_Argument("Invalid value for reseed_interval");
40 }
41
42 if(max_number_of_bytes_per_request == 0 || max_number_of_bytes_per_request > 64 * 1024) {
43 throw Invalid_Argument("Invalid value for max_number_of_bytes_per_request");
44 }
45}
46
47} // namespace
48
49HMAC_DRBG::~HMAC_DRBG() = default;
50
51HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
52 RandomNumberGenerator& underlying_rng,
53 size_t reseed_interval,
55 Stateful_RNG(underlying_rng, reseed_interval),
56 m_mac(std::move(prf)),
57 m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
58 m_security_level(hmac_drbg_security_level(m_mac->output_length())) {
60
62
63 clear();
64}
65
66HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
67 RandomNumberGenerator& underlying_rng,
68 Entropy_Sources& entropy_sources,
69 size_t reseed_interval,
71 Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
72 m_mac(std::move(prf)),
73 m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
74 m_security_level(hmac_drbg_security_level(m_mac->output_length())) {
76
78
79 clear();
80}
81
82HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
83 Entropy_Sources& entropy_sources,
84 size_t reseed_interval,
86 Stateful_RNG(entropy_sources, reseed_interval),
87 m_mac(std::move(prf)),
88 m_max_number_of_bytes_per_request(max_number_of_bytes_per_request),
89 m_security_level(hmac_drbg_security_level(m_mac->output_length())) {
91
93
94 clear();
95}
96
97HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) :
98 m_mac(std::move(prf)),
99 m_max_number_of_bytes_per_request(64 * 1024),
100 m_security_level(hmac_drbg_security_level(m_mac->output_length())) {
102 clear();
103}
104
105HMAC_DRBG::HMAC_DRBG(std::string_view hmac_hash) :
106 m_mac(MessageAuthenticationCode::create_or_throw(fmt("HMAC({})", hmac_hash))),
107 m_max_number_of_bytes_per_request(64 * 1024),
108 m_security_level(hmac_drbg_security_level(m_mac->output_length())) {
109 clear();
110}
111
113 if(m_V.empty()) {
114 const size_t output_length = m_mac->output_length();
115 m_V.resize(output_length);
116 m_T.resize(output_length);
117 }
118
119 std::fill(m_V.begin(), m_V.end(), 0x01);
120 m_mac->set_key(std::vector<uint8_t>(m_V.size(), 0x00));
121}
122
123std::string HMAC_DRBG::name() const {
124 return fmt("HMAC_DRBG({})", m_mac->name());
125}
126
127/*
128* HMAC_DRBG generation
129* See NIST SP800-90A section 10.1.2.5
130*/
131void HMAC_DRBG::generate_output(std::span<uint8_t> output, std::span<const uint8_t> input) {
132 BOTAN_ASSERT_NOMSG(!output.empty());
133
134 if(!input.empty()) {
135 update(input);
136 }
137
138 while(!output.empty()) {
139 const size_t to_copy = std::min(output.size(), m_V.size());
140 m_mac->update(m_V);
141 m_mac->final(m_V);
142 copy_mem(output.data(), m_V.data(), to_copy);
143
144 output = output.subspan(to_copy);
145 }
146
147 update(input);
148}
149
150/*
151* Reset V and the mac key with new values
152* See NIST SP800-90A section 10.1.2.2
153*/
154void HMAC_DRBG::update(std::span<const uint8_t> input) {
155 m_mac->update(m_V);
156 m_mac->update(0x00);
157 if(!input.empty()) {
158 m_mac->update(input);
159 }
160 m_mac->final(m_T);
161 m_mac->set_key(m_T);
162
163 m_mac->update(m_V);
164 m_mac->final(m_V);
165
166 if(!input.empty()) {
167 m_mac->update(m_V);
168 m_mac->update(0x01);
169 m_mac->update(input);
170 m_mac->final(m_T);
171 m_mac->set_key(m_T);
172
173 m_mac->update(m_V);
174 m_mac->final(m_V);
175 }
176}
177
179 return m_security_level;
180}
181} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
std::string name() const override
~HMAC_DRBG() override
size_t security_level() const override
size_t max_number_of_bytes_per_request() const override
Definition hmac_drbg.h:139
HMAC_DRBG(std::unique_ptr< MessageAuthenticationCode > prf)
Definition hmac_drbg.cpp:97
size_t reseed_interval() const
virtual void clear_state()=0
Stateful_RNG(RandomNumberGenerator &rng, Entropy_Sources &entropy_sources, size_t reseed_interval)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53