Kea  2.1.7-git
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>
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 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 
188 private:
190  HashAlgorithm hash_algorithm_;
191 
193  boost::scoped_ptr<Botan::HMAC> hmac_;
194 
196  Botan::secure_vector<Botan::byte> digest_;
197 };
198 
199 HMAC::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 
214 size_t
216  return (impl_->getOutputLength());
217 }
218 
219 void
220 HMAC::update(const void* data, const size_t len) {
221  impl_->update(data, len);
222 }
223 
224 void
225 HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
226  impl_->sign(result, len);
227 }
228 
229 void
230 HMAC::sign(void* result, size_t len) {
231  impl_->sign(result, len);
232 }
233 
234 std::vector<uint8_t>
235 HMAC::sign(size_t len) {
236  return impl_->sign(len);
237 }
238 
239 bool
240 HMAC::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.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
Defines the logger used by the top-level component of kea-lfc.