blob: f6359dde39a28fb8ce1c347684b184810b324e19 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2021 The Chromium Authors
Leonid Baraz06b4bed2021-03-24 06:19:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/reporting/encryption/primitives.h"
6
7#include <cstddef>
8#include <cstdint>
9#include <memory>
10#include <string>
Claudio DeSouzade4d6612024-05-23 10:45:4011#include <string_view>
Leonid Baraz06b4bed2021-03-24 06:19:4412
David Dorwin3f503b82022-04-20 04:07:0313#include "base/check_op.h"
Leonid Baraz06b4bed2021-03-24 06:19:4414#include "crypto/aead.h"
Leonid Baraz06b4bed2021-03-24 06:19:4415#include "third_party/boringssl/src/include/openssl/curve25519.h"
16#include "third_party/boringssl/src/include/openssl/digest.h"
17#include "third_party/boringssl/src/include/openssl/hkdf.h"
18
Leonid Baraz06b4bed2021-03-24 06:19:4419
20namespace reporting {
21
22static_assert(X25519_PRIVATE_KEY_LEN == kKeySize, "X25519 mismatch");
23static_assert(X25519_PUBLIC_VALUE_LEN == kKeySize, "X25519 mismatch");
24static_assert(X25519_SHARED_KEY_LEN == kKeySize, "X25519 mismatch");
25static_assert(ED25519_PRIVATE_KEY_LEN == kSignKeySize, "ED25519 mismatch");
26static_assert(ED25519_PUBLIC_KEY_LEN == kKeySize, "ED25519 mismatch");
27static_assert(ED25519_SIGNATURE_LEN == kSignatureSize, "ED25519 mismatch");
28
29bool ComputeSharedSecret(const uint8_t peer_public_value[kKeySize],
30 uint8_t shared_secret[kKeySize],
31 uint8_t generated_public_value[kKeySize]) {
Leonid Baraz06b4bed2021-03-24 06:19:4432 // Generate new pair of private key and public value.
33 uint8_t out_private_key[kKeySize];
34 X25519_keypair(generated_public_value, out_private_key);
35
36 // Compute shared secret.
37 if (1 != X25519(shared_secret, out_private_key, peer_public_value)) {
38 return false;
39 }
40
41 // Success.
42 return true;
43}
44
45bool ProduceSymmetricKey(const uint8_t shared_secret[kKeySize],
46 uint8_t symmetric_key[kKeySize]) {
Leonid Baraz06b4bed2021-03-24 06:19:4447 // Produce symmetric key from shared secret using HKDF.
48 // Since the original keys were only used once, no salt and context is needed.
49 // Since the keys above are only used once, no salt and context is provided.
50 if (1 != HKDF(symmetric_key, kKeySize, /*digest=*/EVP_sha256(), shared_secret,
51 kKeySize,
52 /*salt=*/nullptr, /*salt_len=*/0,
53 /*info=*/nullptr, /*info_len=*/0)) {
54 return false;
55 }
56
57 // Success.
58 return true;
59}
60
61bool PerformSymmetricEncryption(const uint8_t symmetric_key[kKeySize],
Josh Hilke4996b602023-07-18 17:49:0462 std::string_view input_data,
Leonid Baraz06b4bed2021-03-24 06:19:4463 std::string* output_data) {
Leonid Baraz06b4bed2021-03-24 06:19:4464 // Encrypt the data with symmetric key using AEAD interface.
65 crypto::Aead aead(crypto::Aead::CHACHA20_POLY1305);
Leonid Baraz48447f142023-07-31 19:46:2166 CHECK_EQ(aead.KeyLength(), kKeySize);
Leonid Baraz06b4bed2021-03-24 06:19:4467
68 // Use the symmetric key for data encryption.
69 aead.Init(base::make_span(symmetric_key, kKeySize));
70
71 // Set nonce to 0s, since a symmetric key is only used once.
72 // Note: if we ever start reusing the same symmetric key, we will need
73 // to generate new nonce for every record and transfer it to the peer.
Leonid Baraz48447f142023-07-31 19:46:2174 CHECK_EQ(aead.NonceLength(), kNonceSize);
Leonid Baraz06b4bed2021-03-24 06:19:4475 std::string nonce(kNonceSize, 0);
76
77 // Encrypt the whole record.
78 if (1 != aead.Seal(input_data, nonce, std::string(), output_data)) {
79 return false;
80 }
81
82 // Success. Attach nonce at the head, for compatibility with Tink.
83 output_data->insert(0, nonce);
84 return true;
85}
86
87bool VerifySignature(const uint8_t verification_key[kKeySize],
Josh Hilke4996b602023-07-18 17:49:0488 std::string_view message,
Leonid Baraz06b4bed2021-03-24 06:19:4489 const uint8_t signature[kSignatureSize]) {
Leonid Baraz06b4bed2021-03-24 06:19:4490 // Verify message
91 if (1 != ED25519_verify(reinterpret_cast<const uint8_t*>(message.data()),
92 message.size(), signature, verification_key)) {
93 return false;
94 }
95
96 // Success.
97 return true;
98}
99
100} // namespace reporting