Implement Credentials Generation APIs

PiperOrigin-RevId: 466389238
This commit is contained in:
hai007
2022-08-09 09:56:54 -07:00
committed by Copybara-Service
parent c495cf830f
commit 0a8f1f1c39
5 changed files with 319 additions and 6 deletions
+24 -1
View File
@@ -15,7 +15,10 @@ licenses(["notice"])
cc_library(
name = "internal",
srcs = ["advertisement_decoder.cc"],
srcs = [
"advertisement_decoder.cc",
"credential_manager_impl.cc",
],
hdrs = [
"advertisement_decoder.h",
"broadcast_manager.h",
@@ -30,12 +33,16 @@ cc_library(
"//third_party/nearby/presence:__subpackages__",
],
deps = [
"//internal/crypto",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:logging",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:types",
"//third_party/nearby/presence:action_factory",
"//third_party/nearby/presence:advertisement_factory",
"//third_party/nearby/presence:credential",
"//third_party/nearby/presence:encryption",
"//third_party/nearby/presence:types",
"//third_party/nearby/presence/implementation/mediums",
"//third_party/nearby/presence/proto:credential_cc_proto",
@@ -59,3 +66,19 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "credential_manager_impl_test",
size = "small",
srcs = ["credential_manager_impl_test.cc"],
deps = [
":internal",
"//net/proto2/contrib/parse_proto:testing",
"//internal/crypto",
"//internal/platform/implementation:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"//third_party/nearby/presence:encryption",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
+2 -1
View File
@@ -57,7 +57,8 @@ class CredentialManager {
// storage.
virtual void GenerateCredentials(
proto::DeviceMetadata device_metadata,
std::vector<PresenceIdentity::IdentityType> identity_types,
std::vector<proto::IdentityType> identity_types,
int credential_life_cycle_days, int contiguous_copy_of_credentials,
GenerateCredentialsCallback credentials_generated_cb) = 0;
// Update remote public credentials.
@@ -0,0 +1,173 @@
// 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
@@ -15,7 +15,9 @@
#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
@@ -33,10 +35,17 @@ class CredentialManagerImpl : public CredentialManager {
public:
CredentialManagerImpl() = default;
// AES only supports key sizes of 16, 24 or 32 bytes.
static constexpr int kAuthenticityKeyByteSize = 16;
// Modify this to 12 after use real AES.
static constexpr int kAesGcmIVSize = 16;
void GenerateCredentials(
proto::DeviceMetadata device_metadata,
std::vector<PresenceIdentity::IdentityType> identity_types,
GenerateCredentialsCallback credentials_generated_cb) override {}
std::vector<proto::IdentityType> identity_types,
int credential_life_cycle_days, int contiguous_copy_of_credentials,
GenerateCredentialsCallback credentials_generated_cb);
void UpdateRemotePublicCredentials(
std::string account_name,
@@ -61,8 +70,17 @@ class CredentialManagerImpl : public CredentialManager {
}
private:
location::nearby::CredentialStorage*
credential_storage_; // NOLINT: further impl will use it.
FRIEND_TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully);
std::pair<std::unique_ptr<proto::PrivateCredential>,
std::unique_ptr<proto::PublicCredential>>
CreatePrivateCredential(proto::DeviceMetadata device_metadata,
proto::IdentityType identity_type,
uint64_t start_time_ms, uint64_t end_time_ms);
std::unique_ptr<proto::PublicCredential> CreatePublicCredential(
proto::PrivateCredential* private_credential_ptr,
std::vector<uint8_t>* public_key);
};
} // namespace presence
@@ -0,0 +1,98 @@
// 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 <string>
#include "net/proto2/contrib/parse_proto/testing.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "internal/crypto/encryptor.h"
#include "internal/crypto/symmetric_key.h"
#include "internal/platform/implementation/crypto.h"
#include "third_party/nearby/presence/encryption.h"
namespace nearby {
namespace presence {
using ::location::nearby::Crypto;
using ::nearby::presence::proto::IdentityType::IDENTITY_TYPE_PRIVATE;
using ::proto2::contrib::parse_proto::ParseTestProto;
using ::protobuf_matchers::EqualsProto;
// TODO(b/241926454): Make sure CredentialManager builds with Github.
TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully) {
proto::DeviceMetadata device_metadata = ParseTestProto(R"pb(
stable_device_id: "test_device_id"
;
account_name: "test_account";
device_name: "NP test device";
icon_url: "test_image.test.com"
bluetooth_mac_address: "FF:FF:FF:FF:FF:FF";
device_type: PHONE;
)pb");
CredentialManagerImpl credential_manager;
auto credentials = credential_manager.CreatePrivateCredential(
device_metadata, IDENTITY_TYPE_PRIVATE, /* start_time_ms= */ 0,
/* end_time_ms= */ 1000);
proto::PrivateCredential* private_credential = credentials.first.get();
proto::PublicCredential* public_credential = credentials.second.get();
// Verify the private credential.
EXPECT_THAT(private_credential->device_metadata(),
EqualsProto(device_metadata));
EXPECT_EQ(private_credential->identity_type(), IDENTITY_TYPE_PRIVATE);
EXPECT_FALSE(private_credential->secret_id().empty());
EXPECT_EQ(private_credential->start_time_millis(), 0);
EXPECT_EQ(private_credential->end_time_millis(), 1000);
EXPECT_EQ(private_credential->authenticity_key().size(),
CredentialManagerImpl::kAuthenticityKeyByteSize);
EXPECT_FALSE(private_credential->verification_key().empty());
EXPECT_EQ(private_credential->metadata_encryption_key().size(),
CredentialManagerImpl::kAuthenticityKeyByteSize);
// Verify the public credential.
EXPECT_EQ(public_credential->identity_type(), IDENTITY_TYPE_PRIVATE);
EXPECT_FALSE(public_credential->secret_id().empty());
EXPECT_EQ(private_credential->authenticity_key(),
public_credential->authenticity_key());
EXPECT_EQ(public_credential->start_time_millis(), 0);
EXPECT_EQ(public_credential->end_time_millis(), 1000);
EXPECT_EQ(Crypto::Sha256(private_credential->metadata_encryption_key())
.AsStringView(),
public_credential->metadata_encryption_key_tag());
EXPECT_FALSE(public_credential->verification_key().empty());
EXPECT_FALSE(public_credential->encrypted_metadata_bytes().empty());
// Decrypt the device metadata
crypto::Encryptor encryptor;
auto sym_key = crypto::SymmetricKey::Import(
crypto::SymmetricKey::AES, private_credential->metadata_encryption_key());
EXPECT_TRUE(sym_key.get() != nullptr);
auto iv =
Encryption::CustomizeBytesSize(private_credential->authenticity_key(),
CredentialManagerImpl::kAesGcmIVSize);
encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv);
std::string decrypted_metadata;
EXPECT_TRUE(encryptor.Decrypt(public_credential->encrypted_metadata_bytes(),
&decrypted_metadata));
EXPECT_EQ(private_credential->device_metadata().SerializeAsString(),
decrypted_metadata);
}
} // namespace presence
} // namespace nearby