Kea 2.5.8
botan_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2019 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 <boost/scoped_ptr.hpp>
13
14#include <botan/hmac.h>
15#include <botan/lookup.h>
16
18
19namespace isc {
20namespace cryptolink {
21
24class HMACImpl {
25public:
33 explicit HMACImpl(const void* secret, size_t secret_len,
34 const HashAlgorithm hash_algorithm)
35 : hash_algorithm_(hash_algorithm), hmac_() {
36 Botan::HashFunction* hash;
37 try {
38 const std::string& name =
39 btn::getHashAlgorithmName(hash_algorithm);
40 std::unique_ptr<Botan::HashFunction> hash_ptr =
41 Botan::HashFunction::create(name);
42 if (hash_ptr) {
43 hash = hash_ptr.release();
44 } else {
45 throw Botan::Algorithm_Not_Found(name);
46 }
47 } catch (const Botan::Algorithm_Not_Found&) {
49 "Unknown hash algorithm: " <<
50 static_cast<int>(hash_algorithm));
51 } catch (const Botan::Exception& exc) {
52 isc_throw(LibraryError, "Botan error: " << exc.what());
53 }
54
55 hmac_.reset(new Botan::HMAC(hash));
56
57 // If the key length is larger than the block size, we hash the
58 // key itself first.
59 try {
60 // use a temp var so we don't have blocks spanning
61 // preprocessor directives
62 size_t block_length = hash->hash_block_size();
63 if (secret_len > block_length) {
64 Botan::secure_vector<Botan::byte> hashed_key =
65 hash->process(static_cast<const Botan::byte*>(secret),
66 secret_len);
67 hmac_->set_key(&hashed_key[0], hashed_key.size());
68 } else {
69 // Botan 1.8 considers len 0 a bad key. 1.9 does not,
70 // but we won't accept it anyway, and fail early
71 if (secret_len == 0) {
72 isc_throw(BadKey, "Bad HMAC secret length: 0");
73 }
74 hmac_->set_key(static_cast<const Botan::byte*>(secret),
75 secret_len);
76 }
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
86 }
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
118 if (len > b_result.size()) {
119 len = b_result.size();
120 }
121 result.writeData(&b_result[0], len);
122 } catch (const Botan::Exception& exc) {
123 isc_throw(LibraryError, "Botan error: " << exc.what());
124 }
125 }
126
130 void sign(void* result, size_t len) {
131 try {
132 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
133 size_t output_size = getOutputLength();
134 if (output_size > len) {
135 output_size = len;
136 }
137 std::memcpy(result, &b_result[0], output_size);
138 } catch (const Botan::Exception& exc) {
139 isc_throw(LibraryError, "Botan error: " << exc.what());
140 }
141 }
142
146 std::vector<uint8_t> sign(size_t len) {
147 try {
148 Botan::secure_vector<Botan::byte> b_result(hmac_->final());
149 if (len > b_result.size()) {
150 len = b_result.size();
151 }
152 // Return vector with content. Construct &b_result[len] attempts
153 // to get an address of one element beyond the b_result. Replaced
154 // with the address of first element + len
155 return (std::vector<uint8_t>(&b_result[0], &b_result[0]+len));
156 } catch (const Botan::Exception& exc) {
157 isc_throw(LibraryError, "Botan error: " << exc.what());
158 }
159 }
160
161
165 bool verify(const void* sig, size_t len) {
166 // Botan's verify_mac checks if len matches the output_length,
167 // which causes it to fail for truncated signatures, so we do
168 // the check ourselves
169 try {
170 size_t size = getOutputLength();
171 if (len < 10 || len < size / 2) {
172 return (false);
173 }
174 if (len > size) {
175 len = size;
176 }
177 if (digest_.size() == 0) {
178 digest_ = hmac_->final();
179 }
180 return (Botan::same_mem(&digest_[0],
181 static_cast<const unsigned char*>(sig),
182 len));
183 } catch (const Botan::Exception& exc) {
184 isc_throw(LibraryError, "Botan error: " << exc.what());
185 }
186 }
187
188private:
190 HashAlgorithm hash_algorithm_;
191
193 boost::scoped_ptr<Botan::HMAC> hmac_;
194
196 Botan::secure_vector<Botan::byte> digest_;
197};
198
199HMAC::HMAC(const void* secret, size_t secret_length,
200 const HashAlgorithm hash_algorithm)
201{
202 impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
203}
204
206 delete impl_;
207}
208
211 return (impl_->getHashAlgorithm());
212}
213
214size_t
216 return (impl_->getOutputLength());
217}
218
219void
220HMAC::update(const void* data, const size_t len) {
221 impl_->update(data, len);
222}
223
224void
226 impl_->sign(result, len);
227}
228
229void
230HMAC::sign(void* result, size_t len) {
231 impl_->sign(result, len);
232}
233
234std::vector<uint8_t>
235HMAC::sign(size_t len) {
236 return impl_->sign(len);
237}
238
239bool
240HMAC::verify(const void* sig, const size_t len) {
241 return (impl_->verify(sig, len));
242}
243
244} // namespace cryptolink
245} // 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:347
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:556
#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.