summaryrefslogtreecommitdiff
path: root/chromium/crypto
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/crypto
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/crypto')
-rw-r--r--chromium/crypto/encryptor.cc224
-rw-r--r--chromium/crypto/encryptor.h62
-rw-r--r--chromium/crypto/encryptor_unittest.cc71
-rw-r--r--chromium/crypto/hmac.cc42
-rw-r--r--chromium/crypto/hmac.h25
-rw-r--r--chromium/crypto/hmac_unittest.cc56
-rw-r--r--chromium/crypto/scoped_capi_types.h2
-rw-r--r--chromium/crypto/scoped_nss_types.h2
8 files changed, 279 insertions, 205 deletions
diff --git a/chromium/crypto/encryptor.cc b/chromium/crypto/encryptor.cc
index a58522c9311..d7da5a80199 100644
--- a/chromium/crypto/encryptor.cc
+++ b/chromium/crypto/encryptor.cc
@@ -28,60 +28,9 @@ const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) {
}
}
-// On destruction this class will cleanup the ctx, and also clear the OpenSSL
-// ERR stack as a convenience.
-class ScopedCipherCTX {
- public:
- ScopedCipherCTX() {
- EVP_CIPHER_CTX_init(&ctx_);
- }
- ~ScopedCipherCTX() {
- EVP_CIPHER_CTX_cleanup(&ctx_);
- ClearOpenSSLERRStack(FROM_HERE);
- }
- EVP_CIPHER_CTX* get() { return &ctx_; }
-
- private:
- EVP_CIPHER_CTX ctx_;
-};
-
} // namespace
/////////////////////////////////////////////////////////////////////////////
-// Encyptor::Counter Implementation.
-Encryptor::Counter::Counter(base::StringPiece counter) {
- CHECK(sizeof(counter_) == counter.length());
-
- memcpy(&counter_, counter.data(), sizeof(counter_));
-}
-
-Encryptor::Counter::~Counter() = default;
-
-bool Encryptor::Counter::Increment() {
- uint64_t low_num = base::NetToHost64(counter_.components64[1]);
- uint64_t new_low_num = low_num + 1;
- counter_.components64[1] = base::HostToNet64(new_low_num);
-
- // If overflow occured then increment the most significant component.
- if (new_low_num < low_num) {
- counter_.components64[0] =
- base::HostToNet64(base::NetToHost64(counter_.components64[0]) + 1);
- }
-
- // TODO(hclam): Return false if counter value overflows.
- return true;
-}
-
-void Encryptor::Counter::Write(void* buf) {
- uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf);
- memcpy(buf_ptr, &counter_, sizeof(counter_));
-}
-
-size_t Encryptor::Counter::GetLengthInBytes() const {
- return sizeof(counter_);
-}
-
-/////////////////////////////////////////////////////////////////////////////
// Encryptor Implementation.
Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
@@ -89,132 +38,173 @@ Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
Encryptor::~Encryptor() = default;
bool Encryptor::Init(const SymmetricKey* key, Mode mode, base::StringPiece iv) {
+ return Init(key, mode, base::as_bytes(base::make_span(iv)));
+}
+
+bool Encryptor::Init(const SymmetricKey* key,
+ Mode mode,
+ base::span<const uint8_t> iv) {
DCHECK(key);
DCHECK(mode == CBC || mode == CTR);
EnsureOpenSSLInit();
if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
return false;
+ // CTR mode passes the starting counter separately, via SetCounter().
+ if (mode == CTR && !iv.empty())
+ return false;
if (GetCipherForKey(key) == nullptr)
return false;
key_ = key;
mode_ = mode;
- iv_ = std::string(iv);
+ iv_.assign(iv.begin(), iv.end());
return true;
}
bool Encryptor::Encrypt(base::StringPiece plaintext, std::string* ciphertext) {
- CHECK(!plaintext.empty() || (mode_ == CBC));
- return (mode_ == CTR) ?
- CryptCTR(true, plaintext, ciphertext) :
- Crypt(true, plaintext, ciphertext);
+ CHECK(!plaintext.empty() || mode_ == CBC);
+ return CryptString(/*do_encrypt=*/true, plaintext, ciphertext);
+}
+
+bool Encryptor::Encrypt(base::span<const uint8_t> plaintext,
+ std::vector<uint8_t>* ciphertext) {
+ CHECK(!plaintext.empty() || mode_ == CBC);
+ return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext);
}
bool Encryptor::Decrypt(base::StringPiece ciphertext, std::string* plaintext) {
CHECK(!ciphertext.empty());
- return (mode_ == CTR) ?
- CryptCTR(false, ciphertext, plaintext) :
- Crypt(false, ciphertext, plaintext);
+ return CryptString(/*do_encrypt=*/false, ciphertext, plaintext);
+}
+
+bool Encryptor::Decrypt(base::span<const uint8_t> ciphertext,
+ std::vector<uint8_t>* plaintext) {
+ CHECK(!ciphertext.empty());
+ return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext);
}
bool Encryptor::SetCounter(base::StringPiece counter) {
+ return SetCounter(base::as_bytes(base::make_span(counter)));
+}
+
+bool Encryptor::SetCounter(base::span<const uint8_t> counter) {
if (mode_ != CTR)
return false;
- if (counter.length() != 16u)
+ if (counter.size() != 16u)
return false;
- counter_.reset(new Counter(counter));
+ iv_.assign(counter.begin(), counter.end());
return true;
}
-bool Encryptor::Crypt(bool do_encrypt,
- base::StringPiece input,
- std::string* output) {
- DCHECK(key_); // Must call Init() before En/De-crypt.
- // Work on the result in a local variable, and then only transfer it to
- // |output| on success to ensure no partial data is returned.
+bool Encryptor::CryptString(bool do_encrypt,
+ base::StringPiece input,
+ std::string* output) {
+ size_t out_size = MaxOutput(do_encrypt, input.size());
+ CHECK_GT(out_size + 1, out_size); // Overflow
std::string result;
- output->clear();
+ uint8_t* out_ptr =
+ reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1));
+
+ base::Optional<size_t> len =
+ (mode_ == CTR)
+ ? CryptCTR(do_encrypt, base::as_bytes(base::make_span(input)),
+ base::make_span(out_ptr, out_size))
+ : Crypt(do_encrypt, base::as_bytes(base::make_span(input)),
+ base::make_span(out_ptr, out_size));
+ if (!len)
+ return false;
+
+ result.resize(*len);
+ *output = std::move(result);
+ return true;
+}
+
+bool Encryptor::CryptBytes(bool do_encrypt,
+ base::span<const uint8_t> input,
+ std::vector<uint8_t>* output) {
+ std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size()));
+ base::Optional<size_t> len = (mode_ == CTR)
+ ? CryptCTR(do_encrypt, input, result)
+ : Crypt(do_encrypt, input, result);
+ if (!len)
+ return false;
+
+ result.resize(*len);
+ *output = std::move(result);
+ return true;
+}
+
+size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) {
+ size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0);
+ CHECK_GE(result, length); // Overflow
+ return result;
+}
+
+base::Optional<size_t> Encryptor::Crypt(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output) {
+ DCHECK(key_); // Must call Init() before En/De-crypt.
const EVP_CIPHER* cipher = GetCipherForKey(key_);
DCHECK(cipher); // Already handled in Init();
const std::string& key = key_->key();
- DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length());
- DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length());
+ DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size());
+ DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
- ScopedCipherCTX ctx;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ bssl::ScopedEVP_CIPHER_CTX ctx;
if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
reinterpret_cast<const uint8_t*>(key.data()),
- reinterpret_cast<const uint8_t*>(iv_.data()),
- do_encrypt))
- return false;
+ iv_.data(), do_encrypt)) {
+ return base::nullopt;
+ }
- // When encrypting, add another block size of space to allow for any padding.
- const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0);
- CHECK_GT(output_size, 0u);
- CHECK_GT(output_size + 1, input.size());
- uint8_t* out_ptr =
- reinterpret_cast<uint8_t*>(base::WriteInto(&result, output_size + 1));
+ // Encrypting needs a block size of space to allow for any padding.
+ CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0));
int out_len;
- if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len,
- reinterpret_cast<const uint8_t*>(input.data()),
- input.length()))
- return false;
+ if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
+ input.size()))
+ return base::nullopt;
// Write out the final block plus padding (if any) to the end of the data
// just written.
int tail_len;
- if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len))
- return false;
+ if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
+ return base::nullopt;
out_len += tail_len;
- DCHECK_LE(out_len, static_cast<int>(output_size));
- result.resize(out_len);
-
- output->swap(result);
- return true;
+ DCHECK_LE(out_len, static_cast<int>(output.size()));
+ return out_len;
}
-bool Encryptor::CryptCTR(bool do_encrypt,
- base::StringPiece input,
- std::string* output) {
- if (!counter_.get()) {
+base::Optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output) {
+ if (iv_.size() != AES_BLOCK_SIZE) {
LOG(ERROR) << "Counter value not set in CTR mode.";
- return false;
+ return base::nullopt;
}
AES_KEY aes_key;
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
key_->key().size() * 8, &aes_key) != 0) {
- return false;
+ return base::nullopt;
}
- const size_t out_size = input.size();
- CHECK_GT(out_size, 0u);
- CHECK_GT(out_size + 1, input.size());
-
- std::string result;
- uint8_t* out_ptr =
- reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1));
-
- uint8_t ivec[AES_BLOCK_SIZE] = { 0 };
uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
unsigned int block_offset = 0;
- counter_->Write(ivec);
-
- AES_ctr128_encrypt(reinterpret_cast<const uint8_t*>(input.data()), out_ptr,
- input.size(), &aes_key, ivec, ecount_buf, &block_offset);
-
- // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here.
- SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec),
- AES_BLOCK_SIZE));
-
- output->swap(result);
- return true;
+ // |output| must have room for |input|.
+ CHECK_GE(output.size(), input.size());
+ // Note AES_ctr128_encrypt() will update |iv_|. However, this method discards
+ // |ecount_buf| and |block_offset|, so this is not quite a streaming API.
+ AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key,
+ iv_.data(), ecount_buf, &block_offset);
+ return input.size();
}
} // namespace crypto
diff --git a/chromium/crypto/encryptor.h b/chromium/crypto/encryptor.h
index d84a3875d89..0775e1aa93a 100644
--- a/chromium/crypto/encryptor.h
+++ b/chromium/crypto/encryptor.h
@@ -11,6 +11,8 @@
#include <memory>
#include <string>
+#include "base/containers/span.h"
+#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "crypto/crypto_export.h"
@@ -19,6 +21,10 @@ namespace crypto {
class SymmetricKey;
+// This class implements encryption without authentication, which is usually
+// unsafe. Prefer crypto::Aead for new code. If using this class, prefer the
+// base::span and std::vector overloads over the base::StringPiece and
+// std::string overloads.
class CRYPTO_EXPORT Encryptor {
public:
enum Mode {
@@ -26,30 +32,6 @@ class CRYPTO_EXPORT Encryptor {
CTR,
};
- // This class implements a 128-bits counter to be used in AES-CTR encryption.
- // Only 128-bits counter is supported in this class.
- class CRYPTO_EXPORT Counter {
- public:
- explicit Counter(base::StringPiece counter);
- ~Counter();
-
- // Increment the counter value.
- bool Increment();
-
- // Write the content of the counter to |buf|. |buf| should have enough
- // space for |GetLengthInBytes()|.
- void Write(void* buf);
-
- // Return the length of this counter.
- size_t GetLengthInBytes() const;
-
- private:
- union {
- uint32_t components32[4];
- uint64_t components64[2];
- } counter_;
- };
-
Encryptor();
~Encryptor();
@@ -59,10 +41,13 @@ class CRYPTO_EXPORT Encryptor {
// If |mode| is CBC, |iv| must not be empty; if it is CTR, then |iv| must be
// empty.
bool Init(const SymmetricKey* key, Mode mode, base::StringPiece iv);
+ bool Init(const SymmetricKey* key, Mode mode, base::span<const uint8_t> iv);
// Encrypts |plaintext| into |ciphertext|. |plaintext| may only be empty if
// the mode is CBC.
bool Encrypt(base::StringPiece plaintext, std::string* ciphertext);
+ bool Encrypt(base::span<const uint8_t> plaintext,
+ std::vector<uint8_t>* ciphertext);
// Decrypts |ciphertext| into |plaintext|. |ciphertext| must not be empty.
//
@@ -74,25 +59,42 @@ class CRYPTO_EXPORT Encryptor {
// care to not report decryption failure. Otherwise it could inadvertently
// be used as a padding oracle to attack the cryptosystem.
bool Decrypt(base::StringPiece ciphertext, std::string* plaintext);
+ bool Decrypt(base::span<const uint8_t> ciphertext,
+ std::vector<uint8_t>* plaintext);
// Sets the counter value when in CTR mode. Currently only 128-bits
// counter value is supported.
//
// Returns true only if update was successful.
bool SetCounter(base::StringPiece counter);
+ bool SetCounter(base::span<const uint8_t> counter);
// TODO(albertb): Support streaming encryption.
private:
const SymmetricKey* key_;
Mode mode_;
- std::unique_ptr<Counter> counter_;
- bool Crypt(bool do_encrypt, // Pass true to encrypt, false to decrypt.
- base::StringPiece input,
- std::string* output);
- bool CryptCTR(bool do_encrypt, base::StringPiece input, std::string* output);
- std::string iv_;
+ bool CryptString(bool do_encrypt,
+ base::StringPiece input,
+ std::string* output);
+ bool CryptBytes(bool do_encrypt,
+ base::span<const uint8_t> input,
+ std::vector<uint8_t>* output);
+
+ // On success, these helper functions return the number of bytes written to
+ // |output|.
+ size_t MaxOutput(bool do_encrypt, size_t length);
+ base::Optional<size_t> Crypt(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output);
+ base::Optional<size_t> CryptCTR(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output);
+
+ // In CBC mode, the IV passed to Init(). In CTR mode, the counter value passed
+ // to SetCounter().
+ std::vector<uint8_t> iv_;
};
} // namespace crypto
diff --git a/chromium/crypto/encryptor_unittest.cc b/chromium/crypto/encryptor_unittest.cc
index 0fec305cf2c..b4785cabe0a 100644
--- a/chromium/crypto/encryptor_unittest.cc
+++ b/chromium/crypto/encryptor_unittest.cc
@@ -29,13 +29,21 @@ TEST(EncryptorTest, EncryptDecrypt) {
std::string plaintext("this is the plaintext");
std::string ciphertext;
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
-
EXPECT_LT(0U, ciphertext.size());
std::string decrypted;
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
-
EXPECT_EQ(plaintext, decrypted);
+
+ // Repeat the test with the bytes API.
+ std::vector<uint8_t> plaintext_vec(plaintext.begin(), plaintext.end());
+ std::vector<uint8_t> ciphertext_vec;
+ EXPECT_TRUE(encryptor.Encrypt(plaintext_vec, &ciphertext_vec));
+ EXPECT_LT(0U, ciphertext_vec.size());
+
+ std::vector<uint8_t> decrypted_vec;
+ EXPECT_TRUE(encryptor.Decrypt(ciphertext_vec, &decrypted_vec));
+ EXPECT_EQ(plaintext_vec, decrypted_vec);
}
TEST(EncryptorTest, DecryptWrongKey) {
@@ -211,6 +219,24 @@ void TestAESCTREncrypt(
EXPECT_TRUE(encryptor.Decrypt(encrypted, &decrypted));
EXPECT_EQ(plaintext_str, decrypted);
+
+ // Repeat the test with the bytes API.
+ EXPECT_TRUE(
+ encryptor.SetCounter(base::make_span(init_counter, init_counter_size)));
+ std::vector<uint8_t> encrypted_vec;
+ EXPECT_TRUE(encryptor.Encrypt(base::make_span(plaintext, plaintext_size),
+ &encrypted_vec));
+
+ EXPECT_EQ(ciphertext_size, encrypted_vec.size());
+ EXPECT_EQ(0, memcmp(encrypted_vec.data(), ciphertext, encrypted_vec.size()));
+
+ std::vector<uint8_t> decrypted_vec;
+ EXPECT_TRUE(
+ encryptor.SetCounter(base::make_span(init_counter, init_counter_size)));
+ EXPECT_TRUE(encryptor.Decrypt(encrypted_vec, &decrypted_vec));
+
+ EXPECT_EQ(std::vector<uint8_t>(plaintext, plaintext + plaintext_size),
+ decrypted_vec);
}
void TestAESCTRMultipleDecrypt(
@@ -310,47 +336,6 @@ TEST(EncryptorTest, EncryptDecryptCTR) {
EXPECT_EQ(plaintext, decrypted);
}
-TEST(EncryptorTest, CTRCounter) {
- const int kCounterSize = 16;
- const unsigned char kTest1[] =
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned char buf[16];
-
- // Increment 10 times.
- crypto::Encryptor::Counter counter1(
- std::string(reinterpret_cast<const char*>(kTest1), kCounterSize));
- for (int i = 0; i < 10; ++i)
- counter1.Increment();
- counter1.Write(buf);
- EXPECT_EQ(0, memcmp(buf, kTest1, 15));
- EXPECT_EQ(10, buf[15]);
-
- // Check corner cases.
- const unsigned char kTest2[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- const unsigned char kExpect2[] =
- {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
- crypto::Encryptor::Counter counter2(
- std::string(reinterpret_cast<const char*>(kTest2), kCounterSize));
- counter2.Increment();
- counter2.Write(buf);
- EXPECT_EQ(0, memcmp(buf, kExpect2, kCounterSize));
-
- const unsigned char kTest3[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- const unsigned char kExpect3[] =
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- crypto::Encryptor::Counter counter3(
- std::string(reinterpret_cast<const char*>(kTest3), kCounterSize));
- counter3.Increment();
- counter3.Write(buf);
- EXPECT_EQ(0, memcmp(buf, kExpect3, kCounterSize));
-}
-
// TODO(wtc): add more known-answer tests. Test vectors are available from
// http://www.ietf.org/rfc/rfc3602
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
diff --git a/chromium/crypto/hmac.cc b/chromium/crypto/hmac.cc
index 58abcfab85c..ca7c0f5c587 100644
--- a/chromium/crypto/hmac.cc
+++ b/chromium/crypto/hmac.cc
@@ -57,16 +57,31 @@ bool HMAC::Init(const SymmetricKey* key) {
bool HMAC::Sign(base::StringPiece data,
unsigned char* digest,
size_t digest_length) const {
+ return Sign(base::as_bytes(base::make_span(data)),
+ base::make_span(digest, digest_length));
+}
+
+bool HMAC::Sign(base::span<const uint8_t> data,
+ base::span<uint8_t> digest) const {
DCHECK(initialized_);
- ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest, digest_length);
+ if (digest.size() > DigestLength())
+ return false;
+
+ ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest.data(),
+ digest.size());
return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), key_.data(),
- key_.size(),
- reinterpret_cast<const unsigned char*>(data.data()),
- data.size(), result.safe_buffer(), nullptr);
+ key_.size(), data.data(), data.size(), result.safe_buffer(),
+ nullptr);
}
bool HMAC::Verify(base::StringPiece data, base::StringPiece digest) const {
+ return Verify(base::as_bytes(base::make_span(data)),
+ base::as_bytes(base::make_span(digest)));
+}
+
+bool HMAC::Verify(base::span<const uint8_t> data,
+ base::span<const uint8_t> digest) const {
if (digest.size() != DigestLength())
return false;
return VerifyTruncated(data, digest);
@@ -74,16 +89,25 @@ bool HMAC::Verify(base::StringPiece data, base::StringPiece digest) const {
bool HMAC::VerifyTruncated(base::StringPiece data,
base::StringPiece digest) const {
+ return VerifyTruncated(base::as_bytes(base::make_span(data)),
+ base::as_bytes(base::make_span(digest)));
+}
+
+bool HMAC::VerifyTruncated(base::span<const uint8_t> data,
+ base::span<const uint8_t> digest) const {
if (digest.empty())
return false;
+
size_t digest_length = DigestLength();
- std::unique_ptr<unsigned char[]> computed_digest(
- new unsigned char[digest_length]);
- if (!Sign(data, computed_digest.get(), digest_length))
+ if (digest.size() > digest_length)
+ return false;
+
+ uint8_t computed_digest[EVP_MAX_MD_SIZE];
+ CHECK_LE(digest.size(), size_t{EVP_MAX_MD_SIZE});
+ if (!Sign(data, base::make_span(computed_digest, digest.size())))
return false;
- return SecureMemEqual(digest.data(), computed_digest.get(),
- std::min(digest.size(), digest_length));
+ return SecureMemEqual(digest.data(), computed_digest, digest.size());
}
} // namespace crypto
diff --git a/chromium/crypto/hmac.h b/chromium/crypto/hmac.h
index 760a97341a8..716ab25d2ca 100644
--- a/chromium/crypto/hmac.h
+++ b/chromium/crypto/hmac.h
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Utility class for calculating the HMAC for a given message. We currently
-// only support SHA1 for the hash algorithm, but this can be extended easily.
+// Utility class for calculating the HMAC for a given message. We currently only
+// support SHA-1 and SHA-256 for the hash algorithm, but this can be extended
+// easily. Prefer the base::span and std::vector overloads over the
+// base::StringPiece and std::string overloads.
#ifndef CRYPTO_HMAC_H_
#define CRYPTO_HMAC_H_
@@ -14,6 +16,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/containers/span.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "crypto/crypto_export.h"
@@ -58,16 +61,25 @@ class CRYPTO_EXPORT HMAC {
// Initializes this instance using |key|. Call Init only once. It returns
// false on the second or later calls.
bool Init(base::StringPiece key) WARN_UNUSED_RESULT {
- return Init(reinterpret_cast<const unsigned char*>(key.data()),
- key.size());
+ return Init(base::as_bytes(base::make_span(key)));
+ }
+
+ // Initializes this instance using |key|. Call Init only once. It returns
+ // false on the second or later calls.
+ bool Init(base::span<const uint8_t> key) WARN_UNUSED_RESULT {
+ return Init(key.data(), key.size());
}
// Calculates the HMAC for the message in |data| using the algorithm supplied
// to the constructor and the key supplied to the Init method. The HMAC is
// returned in |digest|, which has |digest_length| bytes of storage available.
+ // If |digest_length| is smaller than DigestLength(), the output will be
+ // truncated. If it is larger, this method will fail.
bool Sign(base::StringPiece data,
unsigned char* digest,
size_t digest_length) const WARN_UNUSED_RESULT;
+ bool Sign(base::span<const uint8_t> data,
+ base::span<uint8_t> digest) const WARN_UNUSED_RESULT;
// Verifies that the HMAC for the message in |data| equals the HMAC provided
// in |digest|, using the algorithm supplied to the constructor and the key
@@ -78,11 +90,16 @@ class CRYPTO_EXPORT HMAC {
// |DigestLength()| bytes long.
bool Verify(base::StringPiece data,
base::StringPiece digest) const WARN_UNUSED_RESULT;
+ bool Verify(base::span<const uint8_t> data,
+ base::span<const uint8_t> digest) const WARN_UNUSED_RESULT;
// Verifies a truncated HMAC, behaving identical to Verify(), except
// that |digest| is allowed to be smaller than |DigestLength()|.
bool VerifyTruncated(base::StringPiece data,
base::StringPiece digest) const WARN_UNUSED_RESULT;
+ bool VerifyTruncated(base::span<const uint8_t> data,
+ base::span<const uint8_t> digest) const
+ WARN_UNUSED_RESULT;
private:
HashAlgorithm hash_alg_;
diff --git a/chromium/crypto/hmac_unittest.cc b/chromium/crypto/hmac_unittest.cc
index 2d39f038364..7e81f0a3855 100644
--- a/chromium/crypto/hmac_unittest.cc
+++ b/chromium/crypto/hmac_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <stddef.h>
+#include <string.h>
#include <string>
@@ -296,3 +297,58 @@ TEST(HMACTest, EmptyKey) {
EXPECT_TRUE(hmac.Verify(
data, base::StringPiece(kExpectedDigest, kSHA1DigestSize)));
}
+
+TEST(HMACTest, TooLong) {
+ // See RFC4231, section 4.7.
+ unsigned char key[131];
+ for (size_t i = 0; i < sizeof(key); ++i)
+ key[i] = 0xaa;
+
+ std::string data = "Test Using Larger Than Block-Size Key - Hash Key First";
+ static uint8_t kKnownHMACSHA256[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+ 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+ 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54};
+
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ ASSERT_TRUE(hmac.Init(key, sizeof(key)));
+
+ // Attempting to write too large of an HMAC is an error.
+ uint8_t calculated_hmac[kSHA256DigestSize + 1];
+ EXPECT_FALSE(hmac.Sign(data, calculated_hmac, sizeof(calculated_hmac)));
+
+ // Attempting to verify too large of an HMAC is an error.
+ memcpy(calculated_hmac, kKnownHMACSHA256, kSHA256DigestSize);
+ calculated_hmac[kSHA256DigestSize] = 0;
+ EXPECT_FALSE(hmac.VerifyTruncated(
+ data,
+ std::string(calculated_hmac, calculated_hmac + sizeof(calculated_hmac))));
+}
+
+TEST(HMACTest, Bytes) {
+ // See RFC4231, section 4.7.
+ std::vector<uint8_t> key(131, 0xaa);
+ std::string data_str =
+ "Test Using Larger Than Block-Size Key - Hash Key First";
+ std::vector<uint8_t> data(data_str.begin(), data_str.end());
+ static uint8_t kKnownHMACSHA256[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+ 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+ 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54};
+
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ ASSERT_TRUE(hmac.Init(key));
+
+ uint8_t calculated_hmac[kSHA256DigestSize];
+ ASSERT_TRUE(hmac.Sign(data, calculated_hmac));
+ EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize));
+
+ EXPECT_TRUE(hmac.Verify(data, calculated_hmac));
+ EXPECT_TRUE(hmac.VerifyTruncated(
+ data, base::make_span(calculated_hmac, kSHA256DigestSize / 2)));
+
+ data[0]++;
+ EXPECT_FALSE(hmac.Verify(data, calculated_hmac));
+ EXPECT_FALSE(hmac.VerifyTruncated(
+ data, base::make_span(calculated_hmac, kSHA256DigestSize / 2)));
+}
diff --git a/chromium/crypto/scoped_capi_types.h b/chromium/crypto/scoped_capi_types.h
index 6d2deb95357..408624b7a65 100644
--- a/chromium/crypto/scoped_capi_types.h
+++ b/chromium/crypto/scoped_capi_types.h
@@ -9,7 +9,7 @@
#include <algorithm>
-#include "base/logging.h"
+#include "base/check.h"
#include "base/macros.h"
#include "base/win/wincrypt_shim.h"
diff --git a/chromium/crypto/scoped_nss_types.h b/chromium/crypto/scoped_nss_types.h
index 2a3a6e1b251..0a663ea7c3b 100644
--- a/chromium/crypto/scoped_nss_types.h
+++ b/chromium/crypto/scoped_nss_types.h
@@ -5,9 +5,9 @@
#ifndef CRYPTO_SCOPED_NSS_TYPES_H_
#define CRYPTO_SCOPED_NSS_TYPES_H_
+#include <certt.h>
#include <keyhi.h>
#include <nss.h>
-#include <nss/certt.h>
#include <pk11pub.h>
#include <plarena.h>