openssl_hmac.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright (C) 2014-2016 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. #include <cryptolink.h>
  7. #include <cryptolink/crypto_hmac.h>
  8. #include <boost/scoped_ptr.hpp>
  9. #include <openssl/hmac.h>
  10. #include <cryptolink/openssl_common.h>
  11. #define KEA_HMAC
  12. #include <cryptolink/openssl_compat.h>
  13. #include <cstring>
  14. namespace isc {
  15. namespace cryptolink {
  16. /// @brief OpenSSL implementation of HMAC. Each method is the counterpart
  17. /// of the HMAC corresponding method.
  18. class HMACImpl {
  19. public:
  20. /// @brief Constructor from a secret and a hash algorithm
  21. ///
  22. /// See constructor of the @ref isc::cryptolink::HMAC class for details.
  23. ///
  24. /// @param secret The secret to sign with
  25. /// @param secret_len The length of the secret
  26. /// @param hash_algorithm The hash algorithm
  27. explicit HMACImpl(const void* secret, size_t secret_len,
  28. const HashAlgorithm hash_algorithm)
  29. : hash_algorithm_(hash_algorithm), md_() {
  30. const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
  31. if (algo == 0) {
  32. isc_throw(UnsupportedAlgorithm,
  33. "Unknown hash algorithm: " <<
  34. static_cast<int>(hash_algorithm));
  35. }
  36. if (secret_len == 0) {
  37. isc_throw(BadKey, "Bad HMAC secret length: 0");
  38. }
  39. md_ = HMAC_CTX_new();
  40. if (md_ == 0) {
  41. isc_throw(LibraryError, "HMAC_CTX_new");
  42. }
  43. if (!HMAC_Init_ex(md_, secret,
  44. static_cast<int>(secret_len),
  45. algo, NULL)) {
  46. isc_throw(LibraryError, "HMAC_Init_ex");
  47. }
  48. }
  49. /// @brief Destructor
  50. ~HMACImpl() {
  51. if (md_) {
  52. HMAC_CTX_free(md_);
  53. }
  54. md_ = 0;
  55. }
  56. /// @brief Returns the HashAlgorithm of the object
  57. HashAlgorithm getHashAlgorithm() const {
  58. return (hash_algorithm_);
  59. }
  60. /// @brief Returns the output size of the digest
  61. ///
  62. /// @return output size of the digest
  63. size_t getOutputLength() const {
  64. int size = HMAC_size(md_);
  65. if (size < 0) {
  66. isc_throw(LibraryError, "HMAC_size");
  67. }
  68. return (static_cast<size_t>(size));
  69. }
  70. /// @brief Add data to digest
  71. ///
  72. /// See @ref isc::cryptolink::HMAC::update() for details.
  73. void update(const void* data, const size_t len) {
  74. if (!HMAC_Update(md_,
  75. static_cast<const unsigned char*>(data),
  76. len)) {
  77. isc_throw(LibraryError, "HMAC_Update");
  78. }
  79. }
  80. /// @brief Calculate the final signature
  81. ///
  82. /// See @ref isc::cryptolink::HMAC::sign() for details.
  83. void sign(isc::util::OutputBuffer& result, size_t len) {
  84. size_t size = getOutputLength();
  85. ossl::SecBuf<unsigned char> digest(size);
  86. if (!HMAC_Final(md_, &digest[0], NULL)) {
  87. isc_throw(LibraryError, "HMAC_Final");
  88. }
  89. if (len > size) {
  90. len = size;
  91. }
  92. result.writeData(&digest[0], len);
  93. }
  94. /// @brief Calculate the final signature
  95. ///
  96. /// See @ref isc::cryptolink::HMAC::sign() for details.
  97. void sign(void* result, size_t len) {
  98. size_t size = getOutputLength();
  99. ossl::SecBuf<unsigned char> digest(size);
  100. if (!HMAC_Final(md_, &digest[0], NULL)) {
  101. isc_throw(LibraryError, "HMAC_Final");
  102. }
  103. if (len > size) {
  104. len = size;
  105. }
  106. std::memcpy(result, &digest[0], len);
  107. }
  108. /// @brief Calculate the final signature
  109. ///
  110. /// See @ref isc::cryptolink::HMAC::sign() for details.
  111. std::vector<uint8_t> sign(size_t len) {
  112. size_t size = getOutputLength();
  113. ossl::SecBuf<unsigned char> digest(size);
  114. if (!HMAC_Final(md_, &digest[0], NULL)) {
  115. isc_throw(LibraryError, "HMAC_Final");
  116. }
  117. if (len < size) {
  118. digest.resize(len);
  119. }
  120. return (std::vector<uint8_t>(digest.begin(), digest.end()));
  121. }
  122. /// @brief Verify an existing signature
  123. ///
  124. /// See @ref isc::cryptolink::HMAC::verify() for details.
  125. bool verify(const void* sig, size_t len) {
  126. // Check the length
  127. size_t size = getOutputLength();
  128. if (len < 10 || len < size / 2) {
  129. return (false);
  130. }
  131. // Get the digest from a copy of the context
  132. HMAC_CTX* tmp = HMAC_CTX_new();
  133. if (tmp == 0) {
  134. isc_throw(LibraryError, "HMAC_CTX_new");
  135. }
  136. if (!HMAC_CTX_copy(tmp, md_)) {
  137. HMAC_CTX_free(tmp);
  138. isc_throw(LibraryError, "HMAC_CTX_copy");
  139. }
  140. ossl::SecBuf<unsigned char> digest(size);
  141. if (!HMAC_Final(tmp, &digest[0], NULL)) {
  142. HMAC_CTX_free(tmp);
  143. isc_throw(LibraryError, "HMAC_Final");
  144. }
  145. HMAC_CTX_free(tmp);
  146. if (len > size) {
  147. len = size;
  148. }
  149. return (digest.same(sig, len));
  150. }
  151. private:
  152. /// @brief The hash algorithm
  153. HashAlgorithm hash_algorithm_;
  154. /// @brief The protected pointer to the OpenSSL HMAC_CTX structure
  155. HMAC_CTX* md_;
  156. };
  157. HMAC::HMAC(const void* secret, size_t secret_length,
  158. const HashAlgorithm hash_algorithm)
  159. {
  160. impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
  161. }
  162. HMAC::~HMAC() {
  163. delete impl_;
  164. }
  165. HashAlgorithm
  166. HMAC::getHashAlgorithm() const {
  167. return (impl_->getHashAlgorithm());
  168. }
  169. size_t
  170. HMAC::getOutputLength() const {
  171. return (impl_->getOutputLength());
  172. }
  173. void
  174. HMAC::update(const void* data, const size_t len) {
  175. impl_->update(data, len);
  176. }
  177. void
  178. HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
  179. impl_->sign(result, len);
  180. }
  181. void
  182. HMAC::sign(void* result, size_t len) {
  183. impl_->sign(result, len);
  184. }
  185. std::vector<uint8_t>
  186. HMAC::sign(size_t len) {
  187. return impl_->sign(len);
  188. }
  189. bool
  190. HMAC::verify(const void* sig, const size_t len) {
  191. return (impl_->verify(sig, len));
  192. }
  193. } // namespace cryptolink
  194. } // namespace isc