Kea 1.5.0
botan_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2011-2018 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 (std::vector<uint8_t>(&b_result[0], &b_result[len]));
153 } catch (const Botan::Exception& exc) {
154 isc_throw(LibraryError, "Botan error: " << exc.what());
155 }
156 }
157
158
162 bool verify(const void* sig, size_t len) {
163 // Botan's verify_mac checks if len matches the output_length,
164 // which causes it to fail for truncated signatures, so we do
165 // the check ourselves
166 try {
167 size_t size = getOutputLength();
168 if (len < 10 || len < size / 2) {
169 return (false);
170 }
171 if (len > size) {
172 len = size;
173 }
174 if (digest_.size() == 0) {
175 digest_ = hmac_->final();
176 }
177 return (Botan::same_mem(&digest_[0],
178 static_cast<const unsigned char*>(sig),
179 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 boost::scoped_ptr<Botan::HMAC> 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
202HMAC::~HMAC() {
203 delete impl_;
204}
205
208 return (impl_->getHashAlgorithm());
209}
210
211size_t
212HMAC::getOutputLength() const {
213 return (impl_->getOutputLength());
214}
215
216void
217HMAC::update(const void* data, const size_t len) {
218 impl_->update(data, len);
219}
220
221void
222HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
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:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:547
#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-dhcp-ddns.