// Copyright 2017 The Chromium Authors. All rights reserved. // 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 "base/logging.h" #include "base/strings/string_piece.h" #include "components/encrypted_messages/encrypted_message.pb.h" #include "crypto/aead.h" #include "crypto/hkdf.h" #include "crypto/random.h" #include "third_party/boringssl/src/include/openssl/curve25519.h" namespace encrypted_messages { namespace { bool GetHkdfSubkeySecret(size_t subkey_length, const uint8_t* private_key, const uint8_t* public_key, base::StringPiece hkdf_label, std::string* secret) { uint8_t shared_secret[X25519_SHARED_KEY_LEN]; if (!X25519(shared_secret, private_key, public_key)) return false; base::StringPiece hkdf_input(reinterpret_cast(shared_secret), sizeof(shared_secret)); *secret = crypto::HkdfSha256(hkdf_input, "", hkdf_label, subkey_length); return true; } } // namespace bool EncryptSerializedMessage(const uint8_t* server_public_key, uint32_t server_public_key_version, base::StringPiece hkdf_label, const std::string& message, EncryptedMessage* encrypted_message) { // Generate an ephemeral key pair to generate a shared secret. uint8_t public_key[X25519_PUBLIC_VALUE_LEN]; uint8_t private_key[X25519_PRIVATE_KEY_LEN]; crypto::RandBytes(private_key, sizeof(private_key)); X25519_public_from_private(public_key, private_key); crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); std::string key; if (!GetHkdfSubkeySecret(aead.KeyLength(), private_key, reinterpret_cast(server_public_key), hkdf_label, &key)) { LOG(ERROR) << "Error getting subkey secret."; return false; } aead.Init(&key); // Use an all-zero nonce because the key is random per-message. std::string nonce(aead.NonceLength(), '\0'); std::string ciphertext; if (!aead.Seal(message, nonce, std::string(), &ciphertext)) { LOG(ERROR) << "Error sealing message."; return false; } encrypted_message->set_encrypted_message(ciphertext); encrypted_message->set_server_public_key_version(server_public_key_version); encrypted_message->set_client_public_key(reinterpret_cast(public_key), sizeof(public_key)); encrypted_message->set_algorithm( EncryptedMessage::AEAD_ECDH_AES_128_CTR_HMAC_SHA256); return true; } // Used only by tests. bool DecryptMessageForTesting(const uint8_t server_private_key[32], base::StringPiece hkdf_label, const EncryptedMessage& encrypted_message, std::string* decrypted_serialized_message) { crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256); std::string key; if (!GetHkdfSubkeySecret(aead.KeyLength(), server_private_key, reinterpret_cast( encrypted_message.client_public_key().data()), hkdf_label, &key)) { LOG(ERROR) << "Error getting subkey secret."; return false; } aead.Init(&key); // Use an all-zero nonce because the key is random per-message. std::string nonce(aead.NonceLength(), 0); return aead.Open(encrypted_message.encrypted_message(), nonce, std::string(), decrypted_serialized_message); } } // namespace encrypted_messages