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