blob: f23428bafa07518f576d0a37979225cd9613a0ff [file] [log] [blame]
// Copyright 2019 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 "chromeos/services/device_sync/cryptauth_key.h"
#include "base/base64.h"
#include "crypto/sha2.h"
namespace chromeos {
namespace device_sync {
namespace {
// Strings used as the DictionaryValue keys in As*DictionaryValue().
const char kHandleDictKey[] = "handle";
const char kStatusDictKey[] = "status";
const char kTypeDictKey[] = "type";
const char kSymmetricKeyDictKey[] = "symmetric_key";
const char kPublicKeyDictKey[] = "public_key";
const char kPrivateKeyDictKey[] = "private_key";
// Returns the base64-encoded SHA256 hash of the input string.
std::string CreateHandle(const std::string& string_to_hash) {
std::string handle;
base::Base64Encode(crypto::SHA256HashString(string_to_hash), &handle);
return handle;
}
bool IsSymmetricKeyType(cryptauthv2::KeyType type) {
return (type == cryptauthv2::KeyType::RAW128 ||
type == cryptauthv2::KeyType::RAW256);
}
bool IsAsymmetricKeyType(cryptauthv2::KeyType type) {
return (type == cryptauthv2::KeyType::P256 ||
type == cryptauthv2::KeyType::CURVE25519);
}
} // namespace
// static
base::Optional<CryptAuthKey> CryptAuthKey::FromDictionary(
const base::Value& dict) {
if (!dict.is_dict())
return base::nullopt;
base::Optional<int> opt_status = dict.FindIntKey(kStatusDictKey);
if (!opt_status)
return base::nullopt;
CryptAuthKey::Status status = static_cast<CryptAuthKey::Status>(*opt_status);
base::Optional<int> opt_type = dict.FindIntKey(kTypeDictKey);
if (!opt_type || !cryptauthv2::KeyType_IsValid(*opt_type))
return base::nullopt;
cryptauthv2::KeyType type = static_cast<cryptauthv2::KeyType>(*opt_type);
const std::string* handle = dict.FindStringKey(kHandleDictKey);
if (!handle || handle->empty())
return base::nullopt;
if (IsSymmetricKeyType(type)) {
const std::string* encoded_symmetric_key =
dict.FindStringKey(kSymmetricKeyDictKey);
if (!encoded_symmetric_key || encoded_symmetric_key->empty())
return base::nullopt;
std::string decoded_symmetric_key;
if (!base::Base64Decode(*encoded_symmetric_key, &decoded_symmetric_key))
return base::nullopt;
return CryptAuthKey(decoded_symmetric_key, status, type, *handle);
}
DCHECK(IsAsymmetricKeyType(type));
const std::string* encoded_public_key = dict.FindStringKey(kPublicKeyDictKey);
const std::string* encoded_private_key =
dict.FindStringKey(kPrivateKeyDictKey);
if (!encoded_public_key || encoded_public_key->empty() ||
!encoded_private_key) {
return base::nullopt;
}
std::string decoded_public_key, decoded_private_key;
if (!base::Base64Decode(*encoded_public_key, &decoded_public_key) ||
!base::Base64Decode(*encoded_private_key, &decoded_private_key)) {
return base::nullopt;
}
return CryptAuthKey(decoded_public_key, decoded_private_key, status, type,
*handle);
}
CryptAuthKey::CryptAuthKey(const std::string& symmetric_key,
Status status,
cryptauthv2::KeyType type,
const base::Optional<std::string>& handle)
: symmetric_key_(symmetric_key),
status_(status),
type_(type),
handle_(handle ? *handle : CreateHandle(symmetric_key)) {
DCHECK(IsSymmetricKey());
DCHECK(!symmetric_key_.empty());
DCHECK(!handle_.empty());
}
CryptAuthKey::CryptAuthKey(const std::string& public_key,
const std::string& private_key,
Status status,
cryptauthv2::KeyType type,
const base::Optional<std::string>& handle)
: public_key_(public_key),
private_key_(private_key),
status_(status),
type_(type),
handle_(handle ? *handle : CreateHandle(public_key)) {
DCHECK(IsAsymmetricKey());
DCHECK(!public_key_.empty());
DCHECK(!handle_.empty());
}
CryptAuthKey::CryptAuthKey(const CryptAuthKey&) = default;
CryptAuthKey::~CryptAuthKey() = default;
bool CryptAuthKey::IsSymmetricKey() const {
return IsSymmetricKeyType(type_);
}
bool CryptAuthKey::IsAsymmetricKey() const {
return IsAsymmetricKeyType(type_);
}
base::Value CryptAuthKey::AsSymmetricKeyDictionary() const {
DCHECK(IsSymmetricKey());
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetKey(kHandleDictKey, base::Value(handle_));
dict.SetKey(kStatusDictKey, base::Value(status_));
dict.SetKey(kTypeDictKey, base::Value(type_));
std::string encoded_symmetric_key;
base::Base64Encode(symmetric_key_, &encoded_symmetric_key);
dict.SetKey(kSymmetricKeyDictKey, base::Value(encoded_symmetric_key));
return dict;
}
base::Value CryptAuthKey::AsAsymmetricKeyDictionary() const {
DCHECK(IsAsymmetricKey());
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetKey(kHandleDictKey, base::Value(handle_));
dict.SetKey(kStatusDictKey, base::Value(status_));
dict.SetKey(kTypeDictKey, base::Value(type_));
std::string encoded_public_key;
base::Base64Encode(public_key_, &encoded_public_key);
dict.SetKey(kPublicKeyDictKey, base::Value(encoded_public_key));
std::string encoded_private_key;
base::Base64Encode(private_key_, &encoded_private_key);
dict.SetKey(kPrivateKeyDictKey, base::Value(encoded_private_key));
return dict;
}
bool CryptAuthKey::operator==(const CryptAuthKey& other) const {
return handle_ == other.handle_ && status_ == other.status_ &&
type_ == other.type_ && symmetric_key_ == other.symmetric_key_ &&
public_key_ == other.public_key_ && private_key_ == other.private_key_;
}
bool CryptAuthKey::operator!=(const CryptAuthKey& other) const {
return !(*this == other);
}
} // namespace device_sync
} // namespace chromeos