Kea 3.2.1-git
botan_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2026 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/mem_ops.h>
14#include <botan/exceptn.h>
15
17
18namespace isc {
19namespace cryptolink {
20
21const std::string
23 switch (algorithm) {
25 return ("HMAC(MD5)");
27 return ("HMAC(SHA-1)");
29 return ("HMAC(SHA-256)");
31 return ("HMAC(SHA-224)");
33 return ("HMAC(SHA-384)");
35 return ("HMAC(SHA-512)");
37 return ("HMAC(Unknown)");
38 }
39 // compiler should have prevented us to reach this, since we have
40 // no default. But we need a return value anyway
41 return ("Unknown");
42}
43
46class HMACImpl {
47public:
55 explicit HMACImpl(const void* secret, size_t secret_len,
56 const HashAlgorithm hash_algorithm)
57 : hash_algorithm_(hash_algorithm), hmac_() {
58 try {
59 const std::string& name =
60 btn::getHmacAlgorithmName(hash_algorithm);
61 hmac_ = Botan::MessageAuthenticationCode::create_or_throw(name);
62 } catch (const Botan::Lookup_Error&) {
64 "Unknown hash algorithm: " <<
65 static_cast<int>(hash_algorithm));
66 } catch (const Botan::Exception& exc) {
67 isc_throw(LibraryError, "Botan error: " << exc.what());
68 }
69
70 try {
71 // Botan 1.8 considers len 0 a bad key. 1.9 does not,
72 // but we won't accept it anyway, and fail early
73 if (secret_len == 0) {
74 isc_throw(BadKey, "Bad HMAC secret length: 0");
75 }
76 hmac_->set_key(static_cast<const Botan::byte*>(secret),
77 secret_len);
78 } catch (const Botan::Invalid_Key_Length& ikl) {
79 isc_throw(BadKey, ikl.what());
80 } catch (const Botan::Exception& exc) {
81 isc_throw(LibraryError, "Botan error: " << exc.what());
82 }
83 }
84
86 ~HMACImpl() = default;
87
90 return (hash_algorithm_);
91 }
92
96 size_t getOutputLength() const {
97 return (hmac_->output_length());
98 }
99
103 void update(const void* data, const size_t len) {
104 try {
105 hmac_->update(static_cast<const Botan::byte*>(data), len);
106 } catch (const Botan::Exception& exc) {
107 isc_throw(LibraryError, "Botan error: " << exc.what());
108 }
109 }
110
114 void sign(isc::util::OutputBuffer& result, size_t len) {
115 try {
116 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
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 if (len > b_result.size()) {
133 len = b_result.size();
134 }
135 std::memcpy(result, &b_result[0], len);
136 } catch (const Botan::Exception& exc) {
137 isc_throw(LibraryError, "Botan error: " << exc.what());
138 }
139 }
140
144 std::vector<uint8_t> sign(size_t len) {
145 try {
146 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
147 if (len > b_result.size()) {
148 len = b_result.size();
149 }
150 // Return vector with content. Construct &b_result[len] attempts
151 // to get an address of one element beyond the b_result. Replaced
152 // with the address of first element + len
153 return (std::vector<uint8_t>(&b_result[0], &b_result[0]+len));
154 } catch (const Botan::Exception& exc) {
155 isc_throw(LibraryError, "Botan error: " << exc.what());
156 }
157 }
158
159
163 bool verify(const void* sig, size_t len) {
164 // Botan's verify_mac checks if len matches the output_length,
165 // which causes it to fail for truncated signatures, so we do
166 // the check ourselves
167 try {
168 size_t size = getOutputLength();
169 if (len < 10 || len < size / 2) {
170 return (false);
171 }
172 if (len > size) {
173 len = size;
174 }
175 if (digest_.size() == 0) {
176 digest_ = hmac_->final();
177 }
178 const uint8_t* sig8 = static_cast<const uint8_t*>(sig);
179 return (Botan::constant_time_compare(&digest_[0], sig8, len));
180 } catch (const Botan::Exception& exc) {
181 isc_throw(LibraryError, "Botan error: " << exc.what());
182 }
183 }
184
185private:
187 HashAlgorithm hash_algorithm_;
188
190 std::unique_ptr<Botan::MessageAuthenticationCode> hmac_;
191
193 Botan::secure_vector<Botan::byte> digest_;
194};
195
196HMAC::HMAC(const void* secret, size_t secret_length,
197 const HashAlgorithm hash_algorithm)
198{
199 impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
200}
201
203 delete impl_;
204}
205
208 return (impl_->getHashAlgorithm());
209}
210
211size_t
213 return (impl_->getOutputLength());
214}
215
216void
217HMAC::update(const void* data, const size_t len) {
218 impl_->update(data, len);
219}
220
221void
223 impl_->sign(result, len);
224}
225
226void
227HMAC::sign(void* result, size_t len) {
228 impl_->sign(result, len);
229}
230
231std::vector<uint8_t>
232HMAC::sign(size_t len) {
233 return impl_->sign(len);
234}
235
236bool
237HMAC::verify(const void* sig, const size_t len) {
238 return (impl_->verify(sig, len));
239}
240
241} // namespace cryptolink
242} // 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:346
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
#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.