diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/crypto | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-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.cc | 224 | ||||
-rw-r--r-- | chromium/crypto/encryptor.h | 62 | ||||
-rw-r--r-- | chromium/crypto/encryptor_unittest.cc | 71 | ||||
-rw-r--r-- | chromium/crypto/hmac.cc | 42 | ||||
-rw-r--r-- | chromium/crypto/hmac.h | 25 | ||||
-rw-r--r-- | chromium/crypto/hmac_unittest.cc | 56 | ||||
-rw-r--r-- | chromium/crypto/scoped_capi_types.h | 2 | ||||
-rw-r--r-- | chromium/crypto/scoped_nss_types.h | 2 |
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> |