mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 15:16:12 -04:00
174 lines
7.0 KiB
C++
174 lines
7.0 KiB
C++
// Copyright 2022 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "third_party/nearby/presence/implementation/credential_manager_impl.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "internal/crypto/ec_private_key.h"
|
|
#include "internal/crypto/encryptor.h"
|
|
#include "internal/crypto/symmetric_key.h"
|
|
#include "internal/platform/base64_utils.h"
|
|
#include "internal/platform/implementation/crypto.h"
|
|
#include "internal/platform/logging.h"
|
|
#include "third_party/nearby/presence/encryption.h"
|
|
|
|
namespace nearby {
|
|
namespace presence {
|
|
namespace {
|
|
using ::location::nearby::Base64Utils;
|
|
using ::location::nearby::Crypto;
|
|
using ::nearby::presence::proto::PrivateCredential;
|
|
using ::nearby::presence::proto::PublicCredential;
|
|
|
|
// Key to retrieve local device's Private/Public Key Credentials from key store.
|
|
constexpr char kPairedKeyAliasPrefix[] = "nearby_presence_paired_key_alias_";
|
|
|
|
} // namespace
|
|
|
|
void CredentialManagerImpl::GenerateCredentials(
|
|
proto::DeviceMetadata device_metadata,
|
|
std::vector<proto::IdentityType> identity_types,
|
|
int credential_life_cycle_days, int contiguous_copy_of_credentials,
|
|
GenerateCredentialsCallback credentials_generated_cb) {
|
|
std::vector<PublicCredential> public_credentials;
|
|
std::vector<PrivateCredential> private_credentials;
|
|
|
|
for (auto identity_type : identity_types) {
|
|
// TODO(b/241587906): Get linux time from the platform (like Android)
|
|
uint64_t start_time_millis = 0;
|
|
const uint64_t gap_millis = credential_life_cycle_days * 24 * 3600 * 1000;
|
|
uint64_t end_time_millis = start_time_millis + gap_millis;
|
|
|
|
for (int index = 0; index < contiguous_copy_of_credentials; index++) {
|
|
auto public_private_credentials = CreatePrivateCredential(
|
|
device_metadata, identity_type, start_time_millis, end_time_millis);
|
|
if (public_private_credentials.first != nullptr) {
|
|
private_credentials.push_back(*public_private_credentials.first);
|
|
public_credentials.push_back(*public_private_credentials.second);
|
|
}
|
|
start_time_millis += gap_millis;
|
|
end_time_millis += gap_millis;
|
|
}
|
|
}
|
|
// TODO(b/241488275) Store all the public and private credentials and call the
|
|
// callback to inform client.
|
|
credentials_generated_cb.credentials_generated_cb(public_credentials);
|
|
}
|
|
|
|
std::pair<std::unique_ptr<PrivateCredential>, std::unique_ptr<PublicCredential>>
|
|
CredentialManagerImpl::CreatePrivateCredential(
|
|
proto::DeviceMetadata device_metadata, proto::IdentityType identity_type,
|
|
uint64_t start_time_ms, uint64_t end_time_ms) {
|
|
auto private_credential_ptr = std::make_unique<PrivateCredential>();
|
|
private_credential_ptr->set_start_time_millis(start_time_ms);
|
|
private_credential_ptr->set_end_time_millis(end_time_ms);
|
|
private_credential_ptr->set_identity_type(identity_type);
|
|
|
|
// Creates an AES key to encrypt the whole broadcast.
|
|
std::string secret_key =
|
|
Encryption::GenerateRandomByteArray(kAuthenticityKeyByteSize);
|
|
private_credential_ptr->set_authenticity_key(secret_key);
|
|
|
|
// Uses SHA-256 algorithm to generate the credential ID from the authenticity
|
|
// key
|
|
auto secret_id = Crypto::Sha256(secret_key);
|
|
if (secret_id.Empty()) {
|
|
NEARBY_LOG(ERROR,
|
|
"Failed to create private credential because it failed to "
|
|
"create a secret id.");
|
|
return std::pair<std::unique_ptr<PrivateCredential>,
|
|
std::unique_ptr<PublicCredential>>(
|
|
std::unique_ptr<PrivateCredential>(nullptr),
|
|
std::unique_ptr<PublicCredential>(nullptr));
|
|
}
|
|
private_credential_ptr->set_secret_id(secret_id.AsStringView());
|
|
|
|
std::string alias = Base64Utils::Encode(secret_id);
|
|
auto prefixedAlias = kPairedKeyAliasPrefix + alias;
|
|
|
|
// Generate key pair. Store the private key in private credential.
|
|
auto key_pair = crypto::ECPrivateKey::Create();
|
|
std::vector<uint8_t> private_key;
|
|
key_pair->ExportPrivateKey(&private_key);
|
|
private_credential_ptr->set_verification_key(
|
|
std::string(private_key.begin(), private_key.end()));
|
|
|
|
// Create an AES key to encrypt the device metadata.
|
|
auto metadata_key =
|
|
Encryption::GenerateRandomByteArray(kAuthenticityKeyByteSize);
|
|
private_credential_ptr->set_metadata_encryption_key(metadata_key);
|
|
|
|
// set device meta data
|
|
*(private_credential_ptr->mutable_device_metadata()) = device_metadata;
|
|
|
|
// Generate the public credential
|
|
std::vector<uint8_t> public_key;
|
|
key_pair->ExportPublicKey(&public_key);
|
|
auto public_credential_ptr =
|
|
CreatePublicCredential(private_credential_ptr.get(), &public_key);
|
|
|
|
return std::pair<std::unique_ptr<PrivateCredential>,
|
|
std::unique_ptr<PublicCredential>>(
|
|
std::move(private_credential_ptr), std::move(public_credential_ptr));
|
|
}
|
|
|
|
std::unique_ptr<proto::PublicCredential>
|
|
CredentialManagerImpl::CreatePublicCredential(
|
|
proto::PrivateCredential* private_credential,
|
|
std::vector<uint8_t>* public_key) {
|
|
auto public_credential_ptr = std::make_unique<PublicCredential>();
|
|
|
|
public_credential_ptr->set_identity_type(private_credential->identity_type());
|
|
public_credential_ptr->set_secret_id(private_credential->secret_id());
|
|
public_credential_ptr->set_authenticity_key(
|
|
private_credential->authenticity_key());
|
|
public_credential_ptr->set_start_time_millis(
|
|
private_credential->start_time_millis());
|
|
public_credential_ptr->set_end_time_millis(
|
|
private_credential->end_time_millis());
|
|
// set up the public key
|
|
public_credential_ptr->set_verification_key(
|
|
std::string(public_key->begin(), public_key->end()));
|
|
|
|
auto metadata_encryption_key_tag =
|
|
Crypto::Sha256(private_credential->metadata_encryption_key());
|
|
public_credential_ptr->set_metadata_encryption_key_tag(
|
|
metadata_encryption_key_tag.AsStringView());
|
|
|
|
// Encrypt the device metadata
|
|
crypto::Encryptor encryptor;
|
|
auto sym_key = crypto::SymmetricKey::Import(
|
|
crypto::SymmetricKey::AES, private_credential->metadata_encryption_key());
|
|
|
|
auto iv = Encryption::CustomizeBytesSize(
|
|
private_credential->authenticity_key(), kAesGcmIVSize);
|
|
// It is GCM in the spec. Here we use CBC instead since GCM is not supported
|
|
// now.
|
|
if (!encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)) {
|
|
NEARBY_LOG(ERROR, "Fails to initialize the encryptor");
|
|
return std::unique_ptr<PublicCredential>(nullptr);
|
|
}
|
|
|
|
encryptor.Encrypt(private_credential->device_metadata().SerializeAsString(),
|
|
public_credential_ptr->mutable_encrypted_metadata_bytes());
|
|
return public_credential_ptr;
|
|
}
|
|
|
|
} // namespace presence
|
|
} // namespace nearby
|