• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "crypto/hmac.h"
11 
12 #include <stddef.h>
13 
14 #include <algorithm>
15 #include <string>
16 
17 #include "base/check.h"
18 #include "base/check_op.h"
19 #include "base/notreached.h"
20 #include "base/stl_util.h"
21 #include "crypto/openssl_util.h"
22 #include "crypto/secure_util.h"
23 #include "crypto/symmetric_key.h"
24 #include "third_party/boringssl/src/include/openssl/hmac.h"
25 
26 namespace crypto {
27 
HMAC(HashAlgorithm hash_alg)28 HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg), initialized_(false) {
29   // Only SHA-1 and SHA-256 hash algorithms are supported now.
30   DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256);
31 }
32 
~HMAC()33 HMAC::~HMAC() {
34   // Zero out key copy.
35   key_.assign(key_.size(), 0);
36   base::STLClearObject(&key_);
37 }
38 
DigestLength() const39 size_t HMAC::DigestLength() const {
40   switch (hash_alg_) {
41     case SHA1:
42       return 20;
43     case SHA256:
44       return 32;
45     default:
46       NOTREACHED();
47   }
48 }
49 
Init(const unsigned char * key,size_t key_length)50 bool HMAC::Init(const unsigned char* key, size_t key_length) {
51   // Init must not be called more than once on the same HMAC object.
52   DCHECK(!initialized_);
53   initialized_ = true;
54   key_.assign(key, key + key_length);
55   return true;
56 }
57 
Init(const SymmetricKey * key)58 bool HMAC::Init(const SymmetricKey* key) {
59   return Init(key->key());
60 }
61 
Sign(std::string_view data,unsigned char * digest,size_t digest_length) const62 bool HMAC::Sign(std::string_view data,
63                 unsigned char* digest,
64                 size_t digest_length) const {
65   return Sign(base::as_byte_span(data), base::span(digest, digest_length));
66 }
67 
Sign(base::span<const uint8_t> data,base::span<uint8_t> digest) const68 bool HMAC::Sign(base::span<const uint8_t> data,
69                 base::span<uint8_t> digest) const {
70   DCHECK(initialized_);
71 
72   if (digest.size() > DigestLength())
73     return false;
74 
75   ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest.data(),
76                                                       digest.size());
77   return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), key_.data(),
78                   key_.size(), data.data(), data.size(), result.safe_buffer(),
79                   nullptr);
80 }
81 
Verify(std::string_view data,std::string_view digest) const82 bool HMAC::Verify(std::string_view data, std::string_view digest) const {
83   return Verify(base::as_byte_span(data), base::as_byte_span(digest));
84 }
85 
Verify(base::span<const uint8_t> data,base::span<const uint8_t> digest) const86 bool HMAC::Verify(base::span<const uint8_t> data,
87                   base::span<const uint8_t> digest) const {
88   if (digest.size() != DigestLength())
89     return false;
90   return VerifyTruncated(data, digest);
91 }
92 
VerifyTruncated(std::string_view data,std::string_view digest) const93 bool HMAC::VerifyTruncated(std::string_view data,
94                            std::string_view digest) const {
95   return VerifyTruncated(base::as_byte_span(data), base::as_byte_span(digest));
96 }
97 
VerifyTruncated(base::span<const uint8_t> data,base::span<const uint8_t> digest) const98 bool HMAC::VerifyTruncated(base::span<const uint8_t> data,
99                            base::span<const uint8_t> digest) const {
100   if (digest.empty())
101     return false;
102 
103   size_t digest_length = DigestLength();
104   if (digest.size() > digest_length)
105     return false;
106 
107   std::array<uint8_t, EVP_MAX_MD_SIZE> computed_buffer;
108   auto computed_digest = base::span(computed_buffer).first(digest.size());
109   if (!Sign(data, computed_digest)) {
110     return false;
111   }
112 
113   return SecureMemEqual(digest, computed_digest);
114 }
115 
116 namespace hmac {
117 
118 namespace {
119 
EVPMDForHashKind(crypto::hash::HashKind kind)120 const EVP_MD* EVPMDForHashKind(crypto::hash::HashKind kind) {
121   switch (kind) {
122     case crypto::hash::HashKind::kSha1:
123       return EVP_sha1();
124     case crypto::hash::HashKind::kSha256:
125       return EVP_sha256();
126     case crypto::hash::HashKind::kSha512:
127       return EVP_sha512();
128   }
129   NOTREACHED();
130 }
131 
132 }  // namespace
133 
Sign(crypto::hash::HashKind kind,base::span<const uint8_t> key,base::span<const uint8_t> data,base::span<uint8_t> hmac)134 void Sign(crypto::hash::HashKind kind,
135           base::span<const uint8_t> key,
136           base::span<const uint8_t> data,
137           base::span<uint8_t> hmac) {
138   const EVP_MD* md = EVPMDForHashKind(kind);
139   CHECK_EQ(hmac.size(), EVP_MD_size(md));
140 
141   bssl::ScopedHMAC_CTX ctx;
142   CHECK(HMAC_Init_ex(ctx.get(), key.data(), key.size(), EVPMDForHashKind(kind),
143                      nullptr));
144   CHECK(HMAC_Update(ctx.get(), data.data(), data.size()));
145   CHECK(HMAC_Final(ctx.get(), hmac.data(), nullptr));
146 }
147 
Verify(crypto::hash::HashKind kind,base::span<const uint8_t> key,base::span<const uint8_t> data,base::span<const uint8_t> hmac)148 bool Verify(crypto::hash::HashKind kind,
149             base::span<const uint8_t> key,
150             base::span<const uint8_t> data,
151             base::span<const uint8_t> hmac) {
152   const EVP_MD* md = EVPMDForHashKind(kind);
153   CHECK_EQ(hmac.size(), EVP_MD_size(md));
154 
155   std::array<uint8_t, EVP_MAX_MD_SIZE> computed_buf;
156   base::span<uint8_t> computed =
157       base::span(computed_buf).first(EVP_MD_size(md));
158 
159   Sign(kind, key, data, computed);
160   return crypto::SecureMemEqual(computed, hmac);
161 }
162 
SignSha1(base::span<const uint8_t> key,base::span<const uint8_t> data)163 std::array<uint8_t, crypto::hash::kSha1Size> SignSha1(
164     base::span<const uint8_t> key,
165     base::span<const uint8_t> data) {
166   std::array<uint8_t, crypto::hash::kSha1Size> result;
167   Sign(crypto::hash::HashKind::kSha1, key, data, result);
168   return result;
169 }
170 
SignSha256(base::span<const uint8_t> key,base::span<const uint8_t> data)171 std::array<uint8_t, crypto::hash::kSha256Size> SignSha256(
172     base::span<const uint8_t> key,
173     base::span<const uint8_t> data) {
174   std::array<uint8_t, crypto::hash::kSha256Size> result;
175   Sign(crypto::hash::HashKind::kSha256, key, data, result);
176   return result;
177 }
178 
SignSha512(base::span<const uint8_t> key,base::span<const uint8_t> data)179 std::array<uint8_t, crypto::hash::kSha512Size> SignSha512(
180     base::span<const uint8_t> key,
181     base::span<const uint8_t> data) {
182   std::array<uint8_t, crypto::hash::kSha512Size> result;
183   Sign(crypto::hash::HashKind::kSha512, key, data, result);
184   return result;
185 }
186 
VerifySha1(base::span<const uint8_t> key,base::span<const uint8_t> data,base::span<const uint8_t,20> hmac)187 bool VerifySha1(base::span<const uint8_t> key,
188                 base::span<const uint8_t> data,
189                 base::span<const uint8_t, 20> hmac) {
190   return Verify(crypto::hash::HashKind::kSha1, key, data, hmac);
191 }
192 
VerifySha256(base::span<const uint8_t> key,base::span<const uint8_t> data,base::span<const uint8_t,32> hmac)193 bool VerifySha256(base::span<const uint8_t> key,
194                   base::span<const uint8_t> data,
195                   base::span<const uint8_t, 32> hmac) {
196   return Verify(crypto::hash::HashKind::kSha256, key, data, hmac);
197 }
198 
VerifySha512(base::span<const uint8_t> key,base::span<const uint8_t> data,base::span<const uint8_t,64> hmac)199 bool VerifySha512(base::span<const uint8_t> key,
200                   base::span<const uint8_t> data,
201                   base::span<const uint8_t, 64> hmac) {
202   return Verify(crypto::hash::HashKind::kSha512, key, data, hmac);
203 }
204 
205 }  // namespace hmac
206 
207 }  // namespace crypto
208