Kea 2.7.5
botan_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <cryptolink.h>
11
12#include <botan/mac.h>
13#include <botan/exceptn.h>
14
16
17namespace isc {
18namespace cryptolink {
19
20const std::string
22 switch (algorithm) {
24 return ("HMAC(MD5)");
26 return ("HMAC(SHA-1)");
28 return ("HMAC(SHA-256)");
30 return ("HMAC(SHA-224)");
32 return ("HMAC(SHA-384)");
34 return ("HMAC(SHA-512)");
36 return ("HMAC(Unknown)");
37 }
38 // compiler should have prevented us to reach this, since we have
39 // no default. But we need a return value anyway
40 return ("Unknown");
41}
42
45class HMACImpl {
46public:
54 explicit HMACImpl(const void* secret, size_t secret_len,
55 const HashAlgorithm hash_algorithm)
56 : hash_algorithm_(hash_algorithm), hmac_() {
57 try {
58 const std::string& name =
59 btn::getHmacAlgorithmName(hash_algorithm);
60 hmac_ = Botan::MessageAuthenticationCode::create_or_throw(name);
61 } catch (const Botan::Lookup_Error&) {
63 "Unknown hash algorithm: " <<
64 static_cast<int>(hash_algorithm));
65 } catch (const Botan::Exception& exc) {
66 isc_throw(LibraryError, "Botan error: " << exc.what());
67 }
68
69 try {
70 // Botan 1.8 considers len 0 a bad key. 1.9 does not,
71 // but we won't accept it anyway, and fail early
72 if (secret_len == 0) {
73 isc_throw(BadKey, "Bad HMAC secret length: 0");
74 }
75 hmac_->set_key(static_cast<const Botan::byte*>(secret),
76 secret_len);
77 } catch (const Botan::Invalid_Key_Length& ikl) {
78 isc_throw(BadKey, ikl.what());
79 } catch (const Botan::Exception& exc) {
80 isc_throw(LibraryError, "Botan error: " << exc.what());
81 }
82 }
83
85 ~HMACImpl() = default;
86
89 return (hash_algorithm_);
90 }
91
95 size_t getOutputLength() const {
96 return (hmac_->output_length());
97 }
98
102 void update(const void* data, const size_t len) {
103 try {
104 hmac_->update(static_cast<const Botan::byte*>(data), len);
105 } catch (const Botan::Exception& exc) {
106 isc_throw(LibraryError, "Botan error: " << exc.what());
107 }
108 }
109
113 void sign(isc::util::OutputBuffer& result, size_t len) {
114 try {
115 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
116
117 if (len > b_result.size()) {
118 len = b_result.size();
119 }
120 result.writeData(&b_result[0], len);
121 } catch (const Botan::Exception& exc) {
122 isc_throw(LibraryError, "Botan error: " << exc.what());
123 }
124 }
125
129 void sign(void* result, size_t len) {
130 try {
131 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
132 size_t output_size = getOutputLength();
133 if (output_size > len) {
134 output_size = len;
135 }
136 std::memcpy(result, &b_result[0], output_size);
137 } catch (const Botan::Exception& exc) {
138 isc_throw(LibraryError, "Botan error: " << exc.what());
139 }
140 }
141
145 std::vector<uint8_t> sign(size_t len) {
146 try {
147 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
148 if (len > b_result.size()) {
149 len = b_result.size();
150 }
151 // Return vector with content. Construct &b_result[len] attempts
152 // to get an address of one element beyond the b_result. Replaced
153 // with the address of first element + len
154 return (std::vector<uint8_t>(&b_result[0], &b_result[0]+len));
155 } catch (const Botan::Exception& exc) {
156 isc_throw(LibraryError, "Botan error: " << exc.what());
157 }
158 }
159
160
164 bool verify(const void* sig, size_t len) {
165 // Botan's verify_mac checks if len matches the output_length,
166 // which causes it to fail for truncated signatures, so we do
167 // the check ourselves
168 try {
169 size_t size = getOutputLength();
170 if (len < 10 || len < size / 2) {
171 return (false);
172 }
173 if (len > size) {
174 len = size;
175 }
176 if (digest_.size() == 0) {
177 digest_ = hmac_->final();
178 }
179 const uint8_t* sig8 = static_cast<const uint8_t*>(sig);
180 return (Botan::constant_time_compare(&digest_[0], sig8, len));
181 } catch (const Botan::Exception& exc) {
182 isc_throw(LibraryError, "Botan error: " << exc.what());
183 }
184 }
185
186private:
188 HashAlgorithm hash_algorithm_;
189
191 std::unique_ptr<Botan::MessageAuthenticationCode> hmac_;
192
194 Botan::secure_vector<Botan::byte> digest_;
195};
196
197HMAC::HMAC(const void* secret, size_t secret_length,
198 const HashAlgorithm hash_algorithm)
199{
200 impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
201}
202
204 delete impl_;
205}
206
209 return (impl_->getHashAlgorithm());
210}
211
212size_t
214 return (impl_->getOutputLength());
215}
216
217void
218HMAC::update(const void* data, const size_t len) {
219 impl_->update(data, len);
220}
221
222void
224 impl_->sign(result, len);
225}
226
227void
228HMAC::sign(void* result, size_t len) {
229 impl_->sign(result, len);
230}
231
232std::vector<uint8_t>
233HMAC::sign(size_t len) {
234 return impl_->sign(len);
235}
236
237bool
238HMAC::verify(const void* sig, const size_t len) {
239 return (impl_->verify(sig, len));
240}
241
242} // namespace cryptolink
243} // namespace isc
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:343
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.