blob: b4369a0223d25f52568cee95abf6902e9f5e568c [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2020 The Chromium Authors
Leonid Baraz2cb92bb2020-08-12 00:09:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Zach Trudo059a3d12021-01-29 21:47:065#include "components/reporting/encryption/decryption.h"
6
Leonid Barazdcdb666902021-01-15 23:46:497#include <limits>
Leonid Baraz06b4bed2021-03-24 06:19:448#include <memory>
Leonid Baraz2cb92bb2020-08-12 00:09:249#include <string>
Leonid Baraz06b4bed2021-03-24 06:19:4410#include <utility>
Leonid Baraz2cb92bb2020-08-12 00:09:2411
Leonid Baraz679cfd02020-08-24 23:03:2912#include "base/containers/span.h"
Leonid Baraz2cb92bb2020-08-12 00:09:2413#include "base/hash/hash.h"
Leonid Baraz679cfd02020-08-24 23:03:2914#include "base/memory/ptr_util.h"
Leonid Baraz6a509132020-10-30 19:30:0015#include "base/rand_util.h"
Leonid Baraz2cb92bb2020-08-12 00:09:2416#include "base/strings/strcat.h"
Leonid Baraz679cfd02020-08-24 23:03:2917#include "base/strings/string_number_conversions.h"
18#include "base/strings/string_piece.h"
Patrick Monette643cdf62021-10-15 19:13:4219#include "base/task/task_runner.h"
Gabriel Charette99f5df32021-03-19 19:55:5520#include "base/task/thread_pool.h"
Hong Xua7c9ad82023-10-30 23:41:5421#include "base/types/expected.h"
Zach Trudo059a3d12021-01-29 21:47:0622#include "components/reporting/encryption/encryption.h"
Leonid Baraz06b4bed2021-03-24 06:19:4423#include "components/reporting/encryption/primitives.h"
24#include "components/reporting/encryption/testing_primitives.h"
Zach Trudo059a3d12021-01-29 21:47:0625#include "components/reporting/util/status.h"
26#include "components/reporting/util/statusor.h"
Leonid Baraz2cb92bb2020-08-12 00:09:2427
28namespace reporting {
Leonid Baraz06b4bed2021-03-24 06:19:4429namespace test {
Leonid Baraz2cb92bb2020-08-12 00:09:2430
Josh Hilke4996b602023-07-18 17:49:0431Decryptor::Handle::Handle(std::string_view shared_secret,
Leonid Baraz679cfd02020-08-24 23:03:2932 scoped_refptr<Decryptor> decryptor)
33 : shared_secret_(shared_secret), decryptor_(decryptor) {}
Leonid Baraz2cb92bb2020-08-12 00:09:2434
Leonid Baraz679cfd02020-08-24 23:03:2935Decryptor::Handle::~Handle() = default;
Leonid Baraz2cb92bb2020-08-12 00:09:2436
Josh Hilke4996b602023-07-18 17:49:0437void Decryptor::Handle::AddToRecord(std::string_view data,
Leonid Baraz679cfd02020-08-24 23:03:2938 base::OnceCallback<void(Status)> cb) {
39 // Add piece of data to the record.
David Benjamin2eb24c242023-05-31 15:29:5040 record_.append(data);
Leonid Baraz679cfd02020-08-24 23:03:2941 std::move(cb).Run(Status::StatusOK());
42}
43
44void Decryptor::Handle::CloseRecord(
Josh Hilke4996b602023-07-18 17:49:0445 base::OnceCallback<void(StatusOr<std::string_view>)> cb) {
Leonid Baraz679cfd02020-08-24 23:03:2946 // Make sure the record self-destructs when returning from this method.
47 const auto self_destruct = base::WrapUnique(this);
48
Leonid Baraz679cfd02020-08-24 23:03:2949 // Produce symmetric key from shared secret using HKDF.
50 // Since the original keys were only used once, no salt and context is needed.
Leonid Baraz06b4bed2021-03-24 06:19:4451 uint8_t out_symmetric_key[kKeySize];
52 if (!ProduceSymmetricKey(
53 reinterpret_cast<const uint8_t*>(shared_secret_.data()),
54 out_symmetric_key)) {
Hong Xua7c9ad82023-10-30 23:41:5455 std::move(cb).Run(base::unexpected(
56 Status(error::INTERNAL, "Symmetric key extraction failed")));
Leonid Baraz679cfd02020-08-24 23:03:2957 return;
58 }
59
Leonid Baraz679cfd02020-08-24 23:03:2960 std::string decrypted;
Leonid Baraz06b4bed2021-03-24 06:19:4461 PerformSymmetricDecryption(out_symmetric_key, record_, &decrypted);
62 record_.clear();
Leonid Baraz679cfd02020-08-24 23:03:2963
64 // Return decrypted record.
65 std::move(cb).Run(decrypted);
66}
67
Josh Hilke4996b602023-07-18 17:49:0468void Decryptor::OpenRecord(std::string_view shared_secret,
Leonid Baraz679cfd02020-08-24 23:03:2969 base::OnceCallback<void(StatusOr<Handle*>)> cb) {
70 std::move(cb).Run(new Handle(shared_secret, this));
71}
72
73StatusOr<std::string> Decryptor::DecryptSecret(
Josh Hilke4996b602023-07-18 17:49:0474 std::string_view private_key,
75 std::string_view peer_public_value) {
Leonid Baraz679cfd02020-08-24 23:03:2976 // Verify the keys.
Leonid Baraz06b4bed2021-03-24 06:19:4477 if (private_key.size() != kKeySize) {
Hong Xua7c9ad82023-10-30 23:41:5478 return base::unexpected(Status(
79 error::FAILED_PRECONDITION,
80 base::StrCat({"Private key size mismatch, expected=",
81 base::NumberToString(kKeySize),
82 " actual=", base::NumberToString(private_key.size())})));
Leonid Baraz679cfd02020-08-24 23:03:2983 }
Leonid Baraz06b4bed2021-03-24 06:19:4484 if (peer_public_value.size() != kKeySize) {
Hong Xua7c9ad82023-10-30 23:41:5485 return base::unexpected(
86 Status(error::FAILED_PRECONDITION,
87 base::StrCat({"Public key size mismatch, expected=",
88 base::NumberToString(kKeySize), " actual=",
89 base::NumberToString(peer_public_value.size())})));
Leonid Baraz679cfd02020-08-24 23:03:2990 }
91
92 // Compute shared secret.
Leonid Baraz06b4bed2021-03-24 06:19:4493 uint8_t out_shared_value[kKeySize];
94 RestoreSharedSecret(
95 reinterpret_cast<const uint8_t*>(private_key.data()),
96 reinterpret_cast<const uint8_t*>(peer_public_value.data()),
97 out_shared_value);
Leonid Baraz679cfd02020-08-24 23:03:2998
Leonid Baraz06b4bed2021-03-24 06:19:4499 return std::string(reinterpret_cast<const char*>(out_shared_value), kKeySize);
Leonid Baraz679cfd02020-08-24 23:03:29100}
101
102Decryptor::Decryptor()
Leonid Baraz2cb92bb2020-08-12 00:09:24103 : keys_sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
104 {base::TaskPriority::BEST_EFFORT, base::MayBlock()})) {
105 DETACH_FROM_SEQUENCE(keys_sequence_checker_);
106}
107
Leonid Baraz679cfd02020-08-24 23:03:29108Decryptor::~Decryptor() = default;
Leonid Baraz2cb92bb2020-08-12 00:09:24109
Leonid Baraz4f79df412020-11-11 23:17:52110void Decryptor::RecordKeyPair(
Josh Hilke4996b602023-07-18 17:49:04111 std::string_view private_key,
112 std::string_view public_key,
Leonid Baraz4f79df412020-11-11 23:17:52113 base::OnceCallback<void(StatusOr<Encryptor::PublicKeyId>)> cb) {
Leonid Baraz2cb92bb2020-08-12 00:09:24114 // Schedule key recording on the sequenced task runner.
115 keys_sequenced_task_runner_->PostTask(
116 FROM_HERE,
117 base::BindOnce(
118 [](std::string public_key, KeyInfo key_info,
Leonid Baraz4f79df412020-11-11 23:17:52119 base::OnceCallback<void(StatusOr<Encryptor::PublicKeyId>)> cb,
Leonid Baraz679cfd02020-08-24 23:03:29120 scoped_refptr<Decryptor> decryptor) {
Leonid Baraz2cb92bb2020-08-12 00:09:24121 DCHECK_CALLED_ON_VALID_SEQUENCE(decryptor->keys_sequence_checker_);
Hong Xu6e3b2702023-12-18 22:52:29122 StatusOr<Encryptor::PublicKeyId> result =
123 CreateUnknownErrorStatusOr();
Leonid Baraz06b4bed2021-03-24 06:19:44124 if (key_info.private_key.size() != kKeySize) {
Hong Xua7c9ad82023-10-30 23:41:54125 result = base::unexpected(Status(
Leonid Baraz679cfd02020-08-24 23:03:29126 error::FAILED_PRECONDITION,
127 base::StrCat(
128 {"Private key size mismatch, expected=",
Leonid Baraz06b4bed2021-03-24 06:19:44129 base::NumberToString(kKeySize), " actual=",
Hong Xua7c9ad82023-10-30 23:41:54130 base::NumberToString(key_info.private_key.size())})));
Leonid Baraz06b4bed2021-03-24 06:19:44131 } else if (public_key.size() != kKeySize) {
Hong Xua7c9ad82023-10-30 23:41:54132 result = base::unexpected(Status(
Leonid Baraz679cfd02020-08-24 23:03:29133 error::FAILED_PRECONDITION,
Leonid Baraz06b4bed2021-03-24 06:19:44134 base::StrCat({"Public key size mismatch, expected=",
135 base::NumberToString(kKeySize), " actual=",
Hong Xua7c9ad82023-10-30 23:41:54136 base::NumberToString(public_key.size())})));
Leonid Baraz6a509132020-10-30 19:30:00137 } else {
138 // Assign a random number to be public key id for testing purposes
Leonid Baraz5fe6f452021-01-08 01:53:40139 // only (in production it will be retrieved from the server as
140 // 'int32').
Leonid Barazdcdb666902021-01-15 23:46:49141 const Encryptor::PublicKeyId public_key_id = base::RandGenerator(
142 std::numeric_limits<Encryptor::PublicKeyId>::max());
Leonid Baraz6a509132020-10-30 19:30:00143 if (!decryptor->keys_.emplace(public_key_id, key_info).second) {
Hong Xua7c9ad82023-10-30 23:41:54144 result = base::unexpected(
145 Status(error::ALREADY_EXISTS,
146 base::StrCat({"Public key='", public_key,
147 "' already recorded"})));
Leonid Baraz6a509132020-10-30 19:30:00148 } else {
149 result = public_key_id;
150 }
Leonid Baraz2cb92bb2020-08-12 00:09:24151 }
152 // Schedule response on a generic thread pool.
153 base::ThreadPool::PostTask(
Leonid Baraz4f79df412020-11-11 23:17:52154 FROM_HERE, base::BindOnce(
155 [](base::OnceCallback<void(
156 StatusOr<Encryptor::PublicKeyId>)> cb,
157 StatusOr<Encryptor::PublicKeyId> result) {
158 std::move(cb).Run(result);
159 },
160 std::move(cb), result));
Leonid Baraz2cb92bb2020-08-12 00:09:24161 },
162 std::string(public_key),
163 KeyInfo{.private_key = std::string(private_key),
164 .time_stamp = base::Time::Now()},
165 std::move(cb), base::WrapRefCounted(this)));
166}
167
Leonid Baraz679cfd02020-08-24 23:03:29168void Decryptor::RetrieveMatchingPrivateKey(
Leonid Baraz4f79df412020-11-11 23:17:52169 Encryptor::PublicKeyId public_key_id,
Leonid Baraz2cb92bb2020-08-12 00:09:24170 base::OnceCallback<void(StatusOr<std::string>)> cb) {
171 // Schedule key retrieval on the sequenced task runner.
172 keys_sequenced_task_runner_->PostTask(
173 FROM_HERE,
174 base::BindOnce(
Leonid Baraz4f79df412020-11-11 23:17:52175 [](Encryptor::PublicKeyId public_key_id,
Leonid Baraz2cb92bb2020-08-12 00:09:24176 base::OnceCallback<void(StatusOr<std::string>)> cb,
Leonid Baraz679cfd02020-08-24 23:03:29177 scoped_refptr<Decryptor> decryptor) {
Leonid Baraz2cb92bb2020-08-12 00:09:24178 DCHECK_CALLED_ON_VALID_SEQUENCE(decryptor->keys_sequence_checker_);
179 auto key_info_it = decryptor->keys_.find(public_key_id);
Leonid Baraz679cfd02020-08-24 23:03:29180 if (key_info_it != decryptor->keys_.end()) {
Leonid Baraz48447f142023-07-31 19:46:21181 CHECK_EQ(key_info_it->second.private_key.size(),
182 static_cast<size_t>(kKeySize));
Leonid Baraz679cfd02020-08-24 23:03:29183 }
Leonid Baraz2cb92bb2020-08-12 00:09:24184 // Schedule response on a generic thread pool.
185 base::ThreadPool::PostTask(
186 FROM_HERE,
187 base::BindOnce(
188 [](base::OnceCallback<void(StatusOr<std::string>)> cb,
189 StatusOr<std::string> result) {
190 std::move(cb).Run(result);
191 },
192 std::move(cb),
193 key_info_it == decryptor->keys_.end()
Hong Xua7c9ad82023-10-30 23:41:54194 ? StatusOr<std::string>(base::unexpected(Status(
195 error::NOT_FOUND, "Matching key not found")))
Leonid Baraz2cb92bb2020-08-12 00:09:24196 : key_info_it->second.private_key));
197 },
198 public_key_id, std::move(cb), base::WrapRefCounted(this)));
199}
200
Leonid Baraz679cfd02020-08-24 23:03:29201StatusOr<scoped_refptr<Decryptor>> Decryptor::Create() {
Leonid Baraz679cfd02020-08-24 23:03:29202 return base::WrapRefCounted(new Decryptor());
203}
204
Leonid Baraz06b4bed2021-03-24 06:19:44205} // namespace test
Leonid Baraz2cb92bb2020-08-12 00:09:24206} // namespace reporting