1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
// 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<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(
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
|