blob: bc00a09e9e2798a8f0f5f8143258284f5333396a [file]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/encrypted_messages/message_encrypter.h"
#include <string_view>
#include "base/logging.h"
#include "base/strings/string_view_util.h"
#include "components/encrypted_messages/encrypted_message.pb.h"
#include "crypto/aead.h"
#include "crypto/kdf.h"
#include "crypto/kex.h"
#include "crypto/keypair.h"
#include "crypto/random.h"
namespace encrypted_messages {
namespace {
constexpr crypto::aead::Algorithm kAeadAlgorithm =
crypto::aead::AES_128_CTR_HMAC_SHA256;
bool GetHkdfSubkeySecret(size_t subkey_length,
const crypto::keypair::PrivateKey& ours,
const crypto::keypair::PublicKey& theirs,
std::string_view hkdf_label,
std::vector<uint8_t>& secret) {
uint8_t shared_secret[32];
crypto::kex::X25519(theirs, ours, shared_secret);
secret.resize(subkey_length);
crypto::kdf::Hkdf(crypto::hash::kSha256, shared_secret, {},
base::as_byte_span(hkdf_label), secret);
return true;
}
} // namespace
bool EncryptSerializedMessage(base::span<const uint8_t, 32> server_public_key,
uint32_t server_public_key_version,
std::string_view hkdf_label,
const std::string& message,
EncryptedMessage* encrypted_message) {
// Generate an ephemeral key pair to generate a shared secret.
auto private_key = crypto::keypair::PrivateKey::GenerateX25519();
auto public_key = private_key.ToX25519PublicKey();
std::vector<uint8_t> key;
if (!GetHkdfSubkeySecret(
crypto::aead::KeySizeFor(kAeadAlgorithm), private_key,
crypto::keypair::PublicKey::FromX25519PublicKey(server_public_key),
hkdf_label, key)) {
LOG(ERROR) << "Error getting subkey secret.";
return false;
}
// Use an all-zero nonce because the key is random per-message.
std::vector<uint8_t> nonce(crypto::aead::NonceSizeFor(kAeadAlgorithm), 0);
std::vector<uint8_t> ciphertext = crypto::aead::Seal(
kAeadAlgorithm, key, base::as_byte_span(message), nonce, {});
encrypted_message->set_encrypted_message(ciphertext.data(),
ciphertext.size());
encrypted_message->set_server_public_key_version(server_public_key_version);
encrypted_message->set_client_public_key(public_key.data(),
public_key.size());
encrypted_message->set_algorithm(
EncryptedMessage::AEAD_ECDH_AES_128_CTR_HMAC_SHA256);
return true;
}
// Used only by tests.
bool DecryptMessageForTesting( // IN-TEST
base::span<const uint8_t, 32> server_private_key,
std::string_view hkdf_label,
const EncryptedMessage& encrypted_message,
std::string* decrypted_serialized_message) {
auto client_public_key_span =
base::as_byte_span(encrypted_message.client_public_key());
if (client_public_key_span.size() != 32) {
return false;
}
std::vector<uint8_t> key;
if (!GetHkdfSubkeySecret(
crypto::aead::KeySizeFor(kAeadAlgorithm),
crypto::keypair::PrivateKey::FromX25519PrivateKey(server_private_key),
crypto::keypair::PublicKey::FromX25519PublicKey(
client_public_key_span.first<32u>()),
hkdf_label, key)) {
LOG(ERROR) << "Error getting subkey secret.";
return false;
}
// Use an all-zero nonce because the key is random per-message.
std::vector<uint8_t> nonce(crypto::aead::NonceSizeFor(kAeadAlgorithm), 0);
auto plaintext = crypto::aead::Open(
kAeadAlgorithm, key,
base::as_byte_span(encrypted_message.encrypted_message()), nonce, {});
if (!plaintext) {
return false;
}
*decrypted_serialized_message = base::as_string_view(*plaintext);
return true;
}
} // namespace encrypted_messages