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