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>
10 #include <cryptolink/crypto_hmac.h>
11 
12 #include <boost/scoped_ptr.hpp>
13 
14 #include <botan/hmac.h>
15 #include <botan/lookup.h>
16 
18 
19 namespace isc {
20 namespace cryptolink {
21 
24 class HMACImpl {
25 public:
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 
185 private:
187  HashAlgorithm hash_algorithm_;
188 
190  boost::scoped_ptr<Botan::HMAC> hmac_;
191 
193  Botan::secure_vector<Botan::byte> digest_;
194 };
195 
196 HMAC::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 
202 HMAC::~HMAC() {
203  delete impl_;
204 }
205 
207 HMAC::getHashAlgorithm() const {
208  return (impl_->getHashAlgorithm());
209 }
210 
211 size_t
212 HMAC::getOutputLength() const {
213  return (impl_->getOutputLength());
214 }
215 
216 void
217 HMAC::update(const void* data, const size_t len) {
218  impl_->update(data, len);
219 }
220 
221 void
222 HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
223  impl_->sign(result, len);
224 }
225 
226 void
227 HMAC::sign(void* result, size_t len) {
228  impl_->sign(result, len);
229 }
230 
231 std::vector<uint8_t>
232 HMAC::sign(size_t len) {
233  return impl_->sign(len);
234 }
235 
236 bool
237 HMAC::verify(const void* sig, const size_t len) {
238  return (impl_->verify(sig, len));
239 }
240 
241 } // namespace cryptolink
242 } // namespace isc
botan_common.h
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition: exceptions/exceptions.cc:32
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::util::OutputBuffer
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
crypto_hmac.h
isc::util::OutputBuffer::writeData
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:547