blob: d7dbd95ef91eb52f965658b60e445f0e49ba1351 [file] [log] [blame]
// Copyright 2019 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/sync/nigori/cryptographer_impl.h"
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "components/sync/nigori/cross_user_sharing_keys.h"
namespace syncer {
// static
std::unique_ptr<CryptographerImpl> CryptographerImpl::CreateEmpty() {
return base::WrapUnique(
new CryptographerImpl(NigoriKeyBag::CreateEmpty(),
/*default_encryption_key_name=*/std::string(),
CrossUserSharingKeys::CreateEmpty()));
}
// static
std::unique_ptr<CryptographerImpl> CryptographerImpl::FromSingleKeyForTesting(
const std::string& passphrase,
const KeyDerivationParams& derivation_params) {
std::unique_ptr<CryptographerImpl> cryptographer = CreateEmpty();
std::string key_name =
cryptographer->EmplaceKey(passphrase, derivation_params);
cryptographer->SelectDefaultEncryptionKey(key_name);
return cryptographer;
}
// static
std::unique_ptr<CryptographerImpl> CryptographerImpl::FromProto(
const sync_pb::CryptographerData& proto) {
NigoriKeyBag key_bag = NigoriKeyBag::CreateFromProto(proto.key_bag());
// TODO(crbug.com/1109221): An invalid local state should be handled in the
// caller instead of CHECK-ing here, e.g. by resetting the local state.
CHECK(proto.default_key_name().empty() ||
key_bag.HasKey(proto.default_key_name()));
CrossUserSharingKeys cross_user_sharing_keys =
CrossUserSharingKeys::CreateFromProto(proto.cross_user_sharing_keys());
return base::WrapUnique(
new CryptographerImpl(std::move(key_bag), proto.default_key_name(),
std::move(cross_user_sharing_keys)));
}
CryptographerImpl::CryptographerImpl(
NigoriKeyBag key_bag,
std::string default_encryption_key_name,
CrossUserSharingKeys cross_user_sharing_keys)
: key_bag_(std::move(key_bag)),
default_encryption_key_name_(std::move(default_encryption_key_name)),
cross_user_sharing_keys_(std::move(cross_user_sharing_keys)) {
DCHECK(default_encryption_key_name_.empty() ||
key_bag_.HasKey(default_encryption_key_name_));
}
CryptographerImpl::~CryptographerImpl() = default;
sync_pb::CryptographerData CryptographerImpl::ToProto() const {
sync_pb::CryptographerData proto;
*proto.mutable_key_bag() = key_bag_.ToProto();
proto.set_default_key_name(default_encryption_key_name_);
*proto.mutable_cross_user_sharing_keys() = cross_user_sharing_keys_.ToProto();
return proto;
}
std::string CryptographerImpl::EmplaceKey(
const std::string& passphrase,
const KeyDerivationParams& derivation_params) {
return key_bag_.AddKey(
Nigori::CreateByDerivation(derivation_params, passphrase));
}
void CryptographerImpl::EmplaceKeyPair(
CrossUserSharingPublicPrivateKeyPair private_key,
uint32_t version) {
cross_user_sharing_keys_.AddKeyPair(std::move(private_key), version);
}
void CryptographerImpl::EmplaceKeysFrom(const NigoriKeyBag& key_bag) {
key_bag_.AddAllUnknownKeysFrom(key_bag);
}
void CryptographerImpl::EmplaceCrossUserSharingKeysFrom(
const CrossUserSharingKeys& keys) {
cross_user_sharing_keys_.AddAllUnknownKeysFrom(keys);
}
void CryptographerImpl::SelectDefaultEncryptionKey(
const std::string& key_name) {
DCHECK(!key_name.empty());
DCHECK(key_bag_.HasKey(key_name));
default_encryption_key_name_ = key_name;
}
void CryptographerImpl::EmplaceAllNigoriKeysFrom(
const CryptographerImpl& other) {
EmplaceKeysFrom(other.key_bag_);
}
void CryptographerImpl::ClearDefaultEncryptionKey() {
default_encryption_key_name_.clear();
}
void CryptographerImpl::ClearAllKeys() {
default_encryption_key_name_.clear();
key_bag_ = NigoriKeyBag::CreateEmpty();
default_cross_user_sharing_key_version_ = absl::nullopt;
cross_user_sharing_keys_ = CrossUserSharingKeys::CreateEmpty();
}
bool CryptographerImpl::HasKey(const std::string& key_name) const {
return key_bag_.HasKey(key_name);
}
bool CryptographerImpl::HasKeyPair(const uint32_t key_pair_version) const {
return cross_user_sharing_keys_.HasKeyPair(key_pair_version);
}
const CrossUserSharingPublicPrivateKeyPair&
CryptographerImpl::GetCrossUserSharingKeyPair(uint32_t version) const {
return cross_user_sharing_keys_.GetKeyPair(version);
}
sync_pb::NigoriKey CryptographerImpl::ExportDefaultKey() const {
DCHECK(CanEncrypt());
return key_bag_.ExportKey(default_encryption_key_name_);
}
std::unique_ptr<CryptographerImpl> CryptographerImpl::Clone() const {
return base::WrapUnique(
new CryptographerImpl(key_bag_.Clone(), default_encryption_key_name_,
cross_user_sharing_keys_.Clone()));
}
size_t CryptographerImpl::KeyBagSizeForTesting() const {
return key_bag_.size();
}
bool CryptographerImpl::CanEncrypt() const {
return !default_encryption_key_name_.empty();
}
bool CryptographerImpl::CanDecrypt(
const sync_pb::EncryptedData& encrypted) const {
return key_bag_.HasKey(encrypted.key_name());
}
std::string CryptographerImpl::GetDefaultEncryptionKeyName() const {
return default_encryption_key_name_;
}
bool CryptographerImpl::EncryptString(const std::string& decrypted,
sync_pb::EncryptedData* encrypted) const {
DCHECK(encrypted);
encrypted->Clear();
if (!CanEncrypt()) {
return false;
}
return key_bag_.EncryptWithKey(default_encryption_key_name_, decrypted,
encrypted);
}
bool CryptographerImpl::DecryptToString(const sync_pb::EncryptedData& encrypted,
std::string* decrypted) const {
DCHECK(decrypted);
return key_bag_.Decrypt(encrypted, decrypted);
}
absl::optional<std::vector<uint8_t>>
CryptographerImpl::AuthEncryptForCrossUserSharing(
base::span<const uint8_t> plaintext,
base::span<const uint8_t> recipient_public_key) const {
if (!default_cross_user_sharing_key_version_.has_value()) {
VLOG(1) << "Default encryption key pair version is not set";
return absl::nullopt;
}
if (!cross_user_sharing_keys_.HasKeyPair(
default_cross_user_sharing_key_version_.value())) {
VLOG(1) << "Encryption key pair is not available";
return absl::nullopt;
}
const CrossUserSharingPublicPrivateKeyPair& encryption_key_pair =
cross_user_sharing_keys_.GetKeyPair(
default_cross_user_sharing_key_version_.value());
return encryption_key_pair.HpkeAuthEncrypt(plaintext, recipient_public_key,
{});
}
absl::optional<std::vector<uint8_t>>
CryptographerImpl::AuthDecryptForCrossUserSharing(
base::span<const uint8_t> encrypted_data,
base::span<const uint8_t> sender_public_key,
const uint32_t recipient_key_version) const {
if (!cross_user_sharing_keys_.HasKeyPair(recipient_key_version)) {
VLOG(1) << "Decryption key pair does not exist: " << recipient_key_version;
return absl::nullopt;
}
const CrossUserSharingPublicPrivateKeyPair& decryption_key_pair =
cross_user_sharing_keys_.GetKeyPair(recipient_key_version);
return decryption_key_pair.HpkeAuthDecrypt(encrypted_data, sender_public_key,
{});
}
void CryptographerImpl::SelectDefaultCrossUserSharingKey(
const uint32_t version) {
default_cross_user_sharing_key_version_ = version;
}
} // namespace syncer