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()) |