Replace encrypting metadata with CBC to AES.

Provide a new API to decrypt the device metadata inside a public credential

PiperOrigin-RevId: 466936093
This commit is contained in:
Xin He
2022-08-11 06:23:49 -07:00
committed by Copybara-Service
parent 30a82350cd
commit 76d45f20db
4 changed files with 98 additions and 29 deletions
@@ -77,6 +77,12 @@ class CredentialManager {
location::nearby::api::CredentialSelector credential_selector,
location::nearby::api::GetPublicCredentialsResultCallback callback) = 0;
// Decrypts the device metadata from a public credential.
// Returns an empty string if decryption fails.
virtual std::string DecryptDeviceMetadata(
std::string device_metadata_encryption_key, std::string authenticity_key,
std::string device_metadata_string) = 0;
// Decrypts Data Elements from an NP advertisement.
// Returns an error if `metadata_key` is not associated with any known
// credentials (identity).
@@ -19,9 +19,9 @@
#include <utility>
#include <vector>
#include "internal/crypto/aead.h"
#include "internal/crypto/ec_private_key.h"
#include "internal/crypto/encryptor.h"
#include "internal/crypto/symmetric_key.h"
#include "internal/crypto/hkdf.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/implementation/crypto.h"
#include "internal/platform/logging.h"
@@ -151,23 +151,76 @@ CredentialManagerImpl::CreatePublicCredential(
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 encrypted_meta_data = EncryptDeviceMetadata(
private_credential->metadata_encryption_key(),
private_credential->authenticity_key(),
private_credential->device_metadata().SerializeAsString());
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");
if (encrypted_meta_data.empty()) {
NEARBY_LOG(ERROR, "Fails to encrypt the device metadata.");
return std::unique_ptr<PublicCredential>(nullptr);
}
encryptor.Encrypt(private_credential->device_metadata().SerializeAsString(),
public_credential_ptr->mutable_encrypted_metadata_bytes());
public_credential_ptr->set_encrypted_metadata_bytes(encrypted_meta_data);
return public_credential_ptr;
}
std::string CredentialManagerImpl::DecryptDeviceMetadata(
std::string device_metadata_encryption_key, std::string authenticity_key,
std::string device_metadata_string) {
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
std::vector<uint8_t> derived_key =
ExtendMetadataEncryptionKey(device_metadata_encryption_key);
aead.Init(derived_key);
auto iv = Encryption::CustomizeBytesSize(
authenticity_key, CredentialManagerImpl::kAesGcmIVSize);
std::vector<uint8_t> iv_bytes(iv.begin(), iv.end());
std::vector<uint8_t> encrypted_device_metadata_bytes(
device_metadata_string.begin(), device_metadata_string.end());
auto result = aead.Open(encrypted_device_metadata_bytes,
/*nonce=*/
iv_bytes,
/*additional_data=*/absl::Span<uint8_t>());
return std::string(result.value().begin(), result.value().end());
}
std::string CredentialManagerImpl::EncryptDeviceMetadata(
std::string device_metadata_encryption_key, std::string authenticity_key,
std::string device_metadata_string) {
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
std::vector<uint8_t> derived_key =
ExtendMetadataEncryptionKey(device_metadata_encryption_key);
aead.Init(derived_key);
auto iv = Encryption::CustomizeBytesSize(authenticity_key, kAesGcmIVSize);
std::vector<uint8_t> iv_bytes(iv.begin(), iv.end());
std::vector<uint8_t> device_metadata_bytes(device_metadata_string.begin(),
device_metadata_string.end());
device_metadata_bytes.resize(device_metadata_string.size());
auto encrypted = aead.Seal(device_metadata_bytes,
/*nonce=*/
iv_bytes,
/*additional_data=*/absl::Span<uint8_t>());
return std::string(encrypted.begin(), encrypted.end());
}
std::vector<uint8_t> CredentialManagerImpl::ExtendMetadataEncryptionKey(
std::string device_metadata_encryption_key) {
return crypto::HkdfSha256(
std::vector<uint8_t>(device_metadata_encryption_key.begin(),
device_metadata_encryption_key.end()),
/*salt=*/absl::Span<uint8_t>(),
/*info=*/absl::Span<uint8_t>(), kNearbyPresenceNumBytesAesGcmKeySize);
}
} // namespace presence
} // namespace nearby
@@ -38,14 +38,17 @@ class CredentialManagerImpl : public CredentialManager {
// AES only supports key sizes of 16, 24 or 32 bytes.
static constexpr int kAuthenticityKeyByteSize = 16;
// Length of key in bytes required by AES-GCM encryption.
static constexpr size_t kNearbyPresenceNumBytesAesGcmKeySize = 32;
// Modify this to 12 after use real AES.
static constexpr int kAesGcmIVSize = 16;
static constexpr int kAesGcmIVSize = 12;
void 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);
GenerateCredentialsCallback credentials_generated_cb) override;
void UpdateRemotePublicCredentials(
std::string account_name,
@@ -63,6 +66,10 @@ class CredentialManagerImpl : public CredentialManager {
location::nearby::api::GetPublicCredentialsResultCallback callback)
override {}
std::string DecryptDeviceMetadata(
std::string device_metadata_encryption_key, std::string authenticity_key,
std::string device_metadata_string) override;
absl::StatusOr<std::string> DecryptDataElements(
absl::string_view metadata_key, absl::string_view salt,
absl::string_view data_elements) override {
@@ -93,6 +100,14 @@ class CredentialManagerImpl : public CredentialManager {
std::unique_ptr<proto::PublicCredential> CreatePublicCredential(
proto::PrivateCredential* private_credential_ptr,
std::vector<uint8_t>* public_key);
std::string EncryptDeviceMetadata(std::string device_metadata_encryption_key,
std::string authenticity_key,
std::string device_metadata_string);
// Extend the key from 16 bytes to 32 bytes.
std::vector<uint8_t> ExtendMetadataEncryptionKey(
std::string device_metadata_encryption_key);
};
} // namespace presence
@@ -20,8 +20,8 @@
#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/crypto/aead.h"
#include "internal/crypto/hkdf.h"
#include "internal/platform/implementation/crypto.h"
#include "presence/encryption.h"
@@ -80,19 +80,14 @@ TEST(CredentialManagerImpl, CreateOneCredentialSuccessfully) {
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));
auto decrypted_device_metadata = credential_manager.DecryptDeviceMetadata(
private_credential->metadata_encryption_key(),
public_credential->authenticity_key(),
public_credential->encrypted_metadata_bytes());
EXPECT_EQ(private_credential->device_metadata().SerializeAsString(),
decrypted_metadata);
decrypted_device_metadata);
}
} // namespace presence
} // namespace nearby