| Index: components/gcm_driver/crypto/gcm_message_cryptographer.cc
|
| diff --git a/components/gcm_driver/crypto/gcm_message_cryptographer.cc b/components/gcm_driver/crypto/gcm_message_cryptographer.cc
|
| index e76a551838c4f15ad2e7aca667c31b1a8971df68..37eacadaee63ae86831af837decac9f1af6b6bb1 100644
|
| --- a/components/gcm_driver/crypto/gcm_message_cryptographer.cc
|
| +++ b/components/gcm_driver/crypto/gcm_message_cryptographer.cc
|
| @@ -4,10 +4,16 @@
|
|
|
| #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
|
|
|
| +#include <openssl/aead.h>
|
| +#include <stddef.h>
|
| +#include <stdint.h>
|
| +
|
| #include <algorithm>
|
| #include <sstream>
|
|
|
| #include "base/logging.h"
|
| +#include "base/numerics/safe_math.h"
|
| +#include "base/strings/string_util.h"
|
| #include "base/sys_byteorder.h"
|
| #include "crypto/hkdf.h"
|
|
|
| @@ -24,6 +30,13 @@ const size_t kDefaultRecordSize = 4096;
|
| // Key size, in bytes, of a valid AEAD_AES_128_GCM key.
|
| const size_t kContentEncryptionKeySize = 16;
|
|
|
| +// The BoringSSL functions used to seal (encrypt) and open (decrypt) a payload
|
| +// follow the same prototype, declared as follows.
|
| +using EVP_AEAD_CTX_TransformFunction =
|
| + int(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
|
| + size_t max_out_len, const uint8_t *nonce, size_t nonce_len,
|
| + const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len);
|
| +
|
| // Creates the info parameter for an HKDF value for the given |content_encoding|
|
| // in accordance with draft-thomson-http-encryption.
|
| //
|
| @@ -190,6 +203,60 @@ bool GCMMessageCryptographer::Decrypt(const base::StringPiece& ciphertext,
|
| return true;
|
| }
|
|
|
| +bool GCMMessageCryptographer::EncryptDecryptRecordInternal(
|
| + Mode mode,
|
| + const base::StringPiece& input,
|
| + const base::StringPiece& key,
|
| + const base::StringPiece& nonce,
|
| + std::string* output) const {
|
| + DCHECK(output);
|
| +
|
| + const EVP_AEAD* aead = EVP_aead_aes_128_gcm();
|
| +
|
| + EVP_AEAD_CTX context;
|
| + if (!EVP_AEAD_CTX_init(&context, aead,
|
| + reinterpret_cast<const uint8_t*>(key.data()),
|
| + key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
|
| + return false;
|
| + }
|
| +
|
| + base::CheckedNumeric<size_t> maximum_output_length(input.size());
|
| + if (mode == ENCRYPT)
|
| + maximum_output_length += kAuthenticationTagBytes;
|
| +
|
| + // WriteInto requires the buffer to finish with a NULL-byte.
|
| + maximum_output_length += 1;
|
| +
|
| + size_t output_length = 0;
|
| + uint8_t* raw_output = reinterpret_cast<uint8_t*>(
|
| + base::WriteInto(output, maximum_output_length.ValueOrDie()));
|
| +
|
| + EVP_AEAD_CTX_TransformFunction* transform_function =
|
| + mode == ENCRYPT ? EVP_AEAD_CTX_seal : EVP_AEAD_CTX_open;
|
| +
|
| + if (!transform_function(
|
| + &context, raw_output, &output_length, output->size(),
|
| + reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
|
| + reinterpret_cast<const uint8_t*>(input.data()), input.size(),
|
| + nullptr, 0)) {
|
| + EVP_AEAD_CTX_cleanup(&context);
|
| + return false;
|
| + }
|
| +
|
| + EVP_AEAD_CTX_cleanup(&context);
|
| +
|
| + base::CheckedNumeric<size_t> expected_output_length(input.size());
|
| + if (mode == ENCRYPT)
|
| + expected_output_length += kAuthenticationTagBytes;
|
| + else
|
| + expected_output_length -= kAuthenticationTagBytes;
|
| +
|
| + DCHECK_EQ(expected_output_length.ValueOrDie(), output_length);
|
| +
|
| + output->resize(output_length);
|
| + return true;
|
| +}
|
| +
|
| std::string GCMMessageCryptographer::DerivePseudoRandomKey(
|
| const base::StringPiece& ikm) const {
|
| if (allow_empty_auth_secret_for_tests_ && auth_secret_.empty())
|
|
|