[email protected] | 2c9f0def | 2012-01-11 23:17:14 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | a5aec2e | 2011-04-30 18:55:18 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "crypto/hmac.h" |
| 6 | |
avi | dd373b8b | 2015-12-21 21:34:43 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
[email protected] | baff1d04 | 2011-07-29 23:28:55 | [diff] [blame] | 9 | #include <algorithm> |
davidben | 6004dc5 | 2017-02-03 04:15:29 | [diff] [blame] | 10 | #include <string> |
[email protected] | baff1d04 | 2011-07-29 23:28:55 | [diff] [blame] | 11 | |
Hans Wennborg | 4d0e180 | 2020-04-24 20:19:43 | [diff] [blame] | 12 | #include "base/check.h" |
| 13 | #include "base/notreached.h" |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 14 | #include "base/stl_util.h" |
| 15 | #include "crypto/openssl_util.h" |
[email protected] | 3cdf6d4 | 2011-10-07 17:02:48 | [diff] [blame] | 16 | #include "crypto/secure_util.h" |
[email protected] | 2c9f0def | 2012-01-11 23:17:14 | [diff] [blame] | 17 | #include "crypto/symmetric_key.h" |
tfarina | 29a3a174 | 2016-10-28 18:47:33 | [diff] [blame] | 18 | #include "third_party/boringssl/src/include/openssl/hmac.h" |
[email protected] | a5aec2e | 2011-04-30 18:55:18 | [diff] [blame] | 19 | |
| 20 | namespace crypto { |
| 21 | |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 22 | HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg), initialized_(false) { |
| 23 | // Only SHA-1 and SHA-256 hash algorithms are supported now. |
| 24 | DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); |
| 25 | } |
| 26 | |
| 27 | HMAC::~HMAC() { |
| 28 | // Zero out key copy. |
| 29 | key_.assign(key_.size(), 0); |
skyostil | 8ef165b | 2016-08-12 13:05:00 | [diff] [blame] | 30 | base::STLClearObject(&key_); |
[email protected] | 2c9f0def | 2012-01-11 23:17:14 | [diff] [blame] | 31 | } |
| 32 | |
[email protected] | a5aec2e | 2011-04-30 18:55:18 | [diff] [blame] | 33 | size_t HMAC::DigestLength() const { |
| 34 | switch (hash_alg_) { |
| 35 | case SHA1: |
| 36 | return 20; |
| 37 | case SHA256: |
| 38 | return 32; |
| 39 | default: |
| 40 | NOTREACHED(); |
| 41 | return 0; |
| 42 | } |
| 43 | } |
| 44 | |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 45 | bool HMAC::Init(const unsigned char* key, size_t key_length) { |
| 46 | // Init must not be called more than once on the same HMAC object. |
| 47 | DCHECK(!initialized_); |
| 48 | initialized_ = true; |
| 49 | key_.assign(key, key + key_length); |
| 50 | return true; |
| 51 | } |
| 52 | |
Chris Mumford | ea3b6c19 | 2017-06-09 18:33:13 | [diff] [blame] | 53 | bool HMAC::Init(const SymmetricKey* key) { |
Chris Mumford | 7bdfcab | 2017-06-20 17:15:14 | [diff] [blame] | 54 | return Init(key->key()); |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 55 | } |
| 56 | |
David Benjamin | cda45eb | 2017-11-06 18:16:52 | [diff] [blame] | 57 | bool HMAC::Sign(base::StringPiece data, |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 58 | unsigned char* digest, |
| 59 | size_t digest_length) const { |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 60 | return Sign(base::as_bytes(base::make_span(data)), |
| 61 | base::make_span(digest, digest_length)); |
| 62 | } |
| 63 | |
| 64 | bool HMAC::Sign(base::span<const uint8_t> data, |
| 65 | base::span<uint8_t> digest) const { |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 66 | DCHECK(initialized_); |
| 67 | |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 68 | if (digest.size() > DigestLength()) |
David Benjamin | 65dd6ff | 2020-06-15 23:22:12 | [diff] [blame] | 69 | return false; |
| 70 | |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 71 | ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest.data(), |
| 72 | digest.size()); |
rsleevi | ffe5a13 | 2016-06-28 01:51:52 | [diff] [blame] | 73 | return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), key_.data(), |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 74 | key_.size(), data.data(), data.size(), result.safe_buffer(), |
| 75 | nullptr); |
svaldez | 9c64146 | 2016-05-02 20:49:05 | [diff] [blame] | 76 | } |
| 77 | |
David Benjamin | cda45eb | 2017-11-06 18:16:52 | [diff] [blame] | 78 | bool HMAC::Verify(base::StringPiece data, base::StringPiece digest) const { |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 79 | return Verify(base::as_bytes(base::make_span(data)), |
| 80 | base::as_bytes(base::make_span(digest))); |
| 81 | } |
| 82 | |
| 83 | bool HMAC::Verify(base::span<const uint8_t> data, |
| 84 | base::span<const uint8_t> digest) const { |
[email protected] | 3292f53 | 2011-07-18 00:39:44 | [diff] [blame] | 85 | if (digest.size() != DigestLength()) |
| 86 | return false; |
[email protected] | baff1d04 | 2011-07-29 23:28:55 | [diff] [blame] | 87 | return VerifyTruncated(data, digest); |
| 88 | } |
| 89 | |
David Benjamin | cda45eb | 2017-11-06 18:16:52 | [diff] [blame] | 90 | bool HMAC::VerifyTruncated(base::StringPiece data, |
| 91 | base::StringPiece digest) const { |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 92 | return VerifyTruncated(base::as_bytes(base::make_span(data)), |
| 93 | base::as_bytes(base::make_span(digest))); |
| 94 | } |
| 95 | |
| 96 | bool HMAC::VerifyTruncated(base::span<const uint8_t> data, |
| 97 | base::span<const uint8_t> digest) const { |
[email protected] | baff1d04 | 2011-07-29 23:28:55 | [diff] [blame] | 98 | if (digest.empty()) |
| 99 | return false; |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 100 | |
[email protected] | baff1d04 | 2011-07-29 23:28:55 | [diff] [blame] | 101 | size_t digest_length = DigestLength(); |
David Benjamin | 65dd6ff | 2020-06-15 23:22:12 | [diff] [blame] | 102 | if (digest.size() > digest_length) |
| 103 | return false; |
| 104 | |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 105 | uint8_t computed_digest[EVP_MAX_MD_SIZE]; |
| 106 | CHECK_LE(digest.size(), size_t{EVP_MAX_MD_SIZE}); |
| 107 | if (!Sign(data, base::make_span(computed_digest, digest.size()))) |
[email protected] | 3292f53 | 2011-07-18 00:39:44 | [diff] [blame] | 108 | return false; |
| 109 | |
David Benjamin | 3efdcb7 | 2020-06-16 22:33:09 | [diff] [blame] | 110 | return SecureMemEqual(digest.data(), computed_digest, digest.size()); |
[email protected] | 3292f53 | 2011-07-18 00:39:44 | [diff] [blame] | 111 | } |
| 112 | |
[email protected] | a5aec2e | 2011-04-30 18:55:18 | [diff] [blame] | 113 | } // namespace crypto |