From 53c504be9dcccf3ede68cdba8d6980683637b15b Mon Sep 17 00:00:00 2001 From: Janusz Sobczak Date: Tue, 25 Oct 2022 16:07:20 -0700 Subject: [PATCH] Use LDT for advertisement encryption. We are still missing the real LDT implementation, so the code is linked with a placeholder code that doesn't do the actual encryption. We also needed to pass the `account_name` to credential manager to choose the correct credentials. PiperOrigin-RevId: 483801163 --- presence/broadcast_request.h | 6 +- presence/implementation/BUILD | 6 + .../implementation/advertisement_factory.cc | 6 +- .../advertisement_factory_test.cc | 36 +++--- .../implementation/base_broadcast_request.cc | 13 +- .../implementation/base_broadcast_request.h | 3 + .../base_broadcast_request_test.cc | 16 ++- presence/implementation/credential_manager.h | 8 +- .../implementation/credential_manager_impl.cc | 56 +++++++++ .../implementation/credential_manager_impl.h | 12 +- .../credential_manager_impl_test.cc | 24 +++- presence/implementation/ldt.cc | 116 ++++++++++++++++++ presence/implementation/ldt.h | 72 +++++++++++ presence/implementation/np_ldt.c | 35 ++++++ 14 files changed, 367 insertions(+), 42 deletions(-) create mode 100644 presence/implementation/ldt.cc create mode 100644 presence/implementation/ldt.h create mode 100644 presence/implementation/np_ldt.c diff --git a/presence/broadcast_request.h b/presence/broadcast_request.h index 02aa64e5..620e51ab 100644 --- a/presence/broadcast_request.h +++ b/presence/broadcast_request.h @@ -45,10 +45,10 @@ struct PresenceBroadcast { // Nearby SDK encrypts Data ELements before broadcasting if a non-public // `PresenceIdentity` is provided. std::vector extended_properties; - }; - // Account name used to select private credentials. - std::string account_name; + // Account name used to select private credentials. + std::string account_name; + }; std::vector sections; }; diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index 1c031b1e..25fbb722 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -22,6 +22,8 @@ cc_library( "base_broadcast_request.cc", "credential_manager_impl.cc", "encryption.cc", + "ldt.cc", + "np_ldt.c", "service_controller_impl.cc", ], hdrs = [ @@ -33,6 +35,8 @@ cc_library( "credential_manager.h", "credential_manager_impl.h", "encryption.h", + "ldt.h", + "np_ldt.h", "scan_manager.h", "service_controller.h", "service_controller_impl.h", @@ -45,6 +49,7 @@ cc_library( "//internal/platform:base", "//internal/platform:comm", "//internal/platform:logging", + "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/implementation:comm", "//internal/platform/implementation:types", @@ -57,6 +62,7 @@ cc_library( "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:variant", ], diff --git a/presence/implementation/advertisement_factory.cc b/presence/implementation/advertisement_factory.cc index c27bfc61..58d1e58c 100644 --- a/presence/implementation/advertisement_factory.cc +++ b/presence/implementation/advertisement_factory.cc @@ -30,7 +30,6 @@ namespace presence { using ::nearby::internal::IdentityType; - namespace { constexpr uint8_t kBaseVersion = 0; @@ -133,8 +132,9 @@ AdvertisementFactory::CreateBaseNpAdvertisement( return result; } absl::StatusOr encrypted = - credential_manager_.EncryptDataElements(presence.identity, request.salt, - unencrypted); + credential_manager_.EncryptDataElements(presence.identity, + presence.account_name, + request.salt, unencrypted); if (!encrypted.ok()) { return encrypted.status(); } diff --git a/presence/implementation/advertisement_factory_test.cc b/presence/implementation/advertisement_factory_test.cc index f945300f..495baf62 100644 --- a/presence/implementation/advertisement_factory_test.cc +++ b/presence/implementation/advertisement_factory_test.cc @@ -39,12 +39,13 @@ using ::testing::status::StatusIs; class MockCredentialManager : public CredentialManagerImpl { public: MOCK_METHOD(absl::StatusOr, EncryptDataElements, - (IdentityType identity, absl::string_view salt, - absl::string_view data_elements), + (IdentityType identity, absl::string_view account_name, + absl::string_view salt, absl::string_view data_elements), (override)); }; TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { + std::string account_name = "Test account"; std::string salt = "AB"; std::string metadata_key = absl::HexStringToBytes("1011121314151617181920212223"); @@ -55,12 +56,13 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) + .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) .SetAction(action)); - EXPECT_CALL( - credential_manager, - EncryptDataElements(kIdentity, salt, absl::HexStringToBytes("36050080"))) + EXPECT_CALL(credential_manager, + EncryptDataElements(kIdentity, account_name, salt, + absl::HexStringToBytes("36050080"))) .WillOnce(Return(metadata_key + absl::HexStringToBytes("50515253"))); AdvertisementFactory factory(&credential_manager); @@ -105,6 +107,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) { } TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionFails) { + std::string account_name = "Test account"; std::string salt = "AB"; NiceMock credential_manager; constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE; @@ -113,12 +116,13 @@ TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionFails) { Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) + .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) .SetAction(action)); - EXPECT_CALL( - credential_manager, - EncryptDataElements(kIdentity, salt, absl::HexStringToBytes("36050080"))) + EXPECT_CALL(credential_manager, + EncryptDataElements(kIdentity, account_name, salt, + absl::HexStringToBytes("36050080"))) .WillOnce(Return(absl::OutOfRangeError("failed"))); AdvertisementFactory factory(&credential_manager); @@ -128,6 +132,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionFails) { TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionReturnsTooMuchData) { + std::string account_name = "Test account"; std::string salt = "AB"; NiceMock credential_manager; constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE; @@ -136,12 +141,13 @@ TEST(AdvertisementFactory, Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) + .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) .SetAction(action)); - EXPECT_CALL( - credential_manager, - EncryptDataElements(kIdentity, salt, absl::HexStringToBytes("36050080"))) + EXPECT_CALL(credential_manager, + EncryptDataElements(kIdentity, account_name, salt, + absl::HexStringToBytes("36050080"))) .WillOnce(Return(absl::HexStringToBytes( "deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead" "deaddeaddeaddeaddeaddeaddead"))); @@ -153,6 +159,7 @@ TEST(AdvertisementFactory, TEST(AdvertisementFactory, CreateAdvertisementFailsWhenEncryptionReturnsTooLittleData) { + std::string account_name = "Test account"; std::string salt = "AB"; std::string metadata_key = absl::HexStringToBytes("1011121314151617181920212223"); @@ -164,12 +171,13 @@ TEST(AdvertisementFactory, Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) + .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) .SetAction(action)); - EXPECT_CALL( - credential_manager, - EncryptDataElements(kIdentity, salt, absl::HexStringToBytes("36050080"))) + EXPECT_CALL(credential_manager, + EncryptDataElements(kIdentity, account_name, salt, + absl::HexStringToBytes("36050080"))) .WillOnce(Return(metadata_key)); AdvertisementFactory factory(&credential_manager); diff --git a/presence/implementation/base_broadcast_request.cc b/presence/implementation/base_broadcast_request.cc index 7a8c3b13..7da31509 100644 --- a/presence/implementation/base_broadcast_request.cc +++ b/presence/implementation/base_broadcast_request.cc @@ -54,9 +54,15 @@ BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetPowerMode( return *this; } +BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetAccountName( + absl::string_view account_name) { + account_name_ = account_name; + return *this; +} + BasePresenceRequestBuilder::operator BaseBroadcastRequest() const { - BaseBroadcastRequest::BasePresence presence{.identity = identity_, - .action = action_}; + BaseBroadcastRequest::BasePresence presence{ + .identity = identity_, .action = action_, .account_name = account_name_}; BaseBroadcastRequest broadcast_request{ .variant = presence, .salt = salt_.size() == kSaltSize @@ -85,7 +91,8 @@ absl::StatusOr BaseBroadcastRequest::Create( BasePresenceRequestBuilder(section.identity) .SetTxPower(request.tx_power) .SetAction(ActionFactory::CreateAction(section.extended_properties)) - .SetPowerMode(request.power_mode)); + .SetPowerMode(request.power_mode) + .SetAccountName(section.account_name)); } return absl::UnimplementedError("Request not supported"); } diff --git a/presence/implementation/base_broadcast_request.h b/presence/implementation/base_broadcast_request.h index 17406a07..0915419f 100644 --- a/presence/implementation/base_broadcast_request.h +++ b/presence/implementation/base_broadcast_request.h @@ -49,6 +49,7 @@ struct BaseBroadcastRequest { struct BasePresence { nearby::internal::IdentityType identity; Action action; + std::string account_name; }; struct BaseFastPair { struct Discoverable { @@ -80,6 +81,7 @@ class BasePresenceRequestBuilder { BasePresenceRequestBuilder& SetTxPower(int8_t tx_power); BasePresenceRequestBuilder& SetAction(const Action& action); BasePresenceRequestBuilder& SetPowerMode(PowerMode power_mode); + BasePresenceRequestBuilder& SetAccountName(absl::string_view account_name); explicit operator BaseBroadcastRequest() const; @@ -89,6 +91,7 @@ class BasePresenceRequestBuilder { int8_t tx_power_ = kUnspecifiedTxPower; Action action_; PowerMode power_mode_ = PowerMode::kNoPower; + std::string account_name_; }; } // namespace presence diff --git a/presence/implementation/base_broadcast_request_test.cc b/presence/implementation/base_broadcast_request_test.cc index 10566770..bcad3161 100644 --- a/presence/implementation/base_broadcast_request_test.cc +++ b/presence/implementation/base_broadcast_request_test.cc @@ -14,6 +14,8 @@ #include "presence/implementation/base_broadcast_request.h" +#include + #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" @@ -46,15 +48,14 @@ TEST(BroadcastRequestTest, CreateFromPresenceRequest) { constexpr int8_t kTxPower = 30; constexpr uint32_t kExpectedAction = (1 << 23); // encoded kActiveUnlockAction + std::string account_name = "Test account"; PresenceBroadcast::BroadcastSection section = { .identity = internal::IDENTITY_TYPE_PUBLIC, - .extended_properties = { - DataElement(DataElement(ActionBit::kActiveUnlockAction))}}; + .extended_properties = {DataElement( + DataElement(ActionBit::kActiveUnlockAction))}, + .account_name = account_name}; PresenceBroadcast presence_request = {.sections = {section}}; - BroadcastRequest input = { - .tx_power = kTxPower, - .variant = presence_request, - }; + BroadcastRequest input = {.tx_power = kTxPower, .variant = presence_request}; absl::StatusOr request = BaseBroadcastRequest::Create(input); @@ -67,6 +68,9 @@ TEST(BroadcastRequestTest, CreateFromPresenceRequest) { EXPECT_THAT(absl::get(request->variant) .action.action, kExpectedAction); + EXPECT_THAT(absl::get(request->variant) + .account_name, + account_name); } TEST(BroadcastRequestTest, CreateFromEmptyPresenceRequestFails) { diff --git a/presence/implementation/credential_manager.h b/presence/implementation/credential_manager.h index 8aefef56..5e032c74 100644 --- a/presence/implementation/credential_manager.h +++ b/presence/implementation/credential_manager.h @@ -81,11 +81,11 @@ class CredentialManager { virtual absl::StatusOr DecryptDataElements( absl::string_view salt, absl::string_view data_elements) = 0; - // Encrypts `data_elements` using certificate associated with `identity` and - // `salt`. + // Encrypts `data_elements` using certificate associated with `identity`, + // `account_name` and `salt`. virtual absl::StatusOr EncryptDataElements( - nearby::internal::IdentityType identity, absl::string_view salt, - absl::string_view data_elements) = 0; + nearby::internal::IdentityType identity, absl::string_view account_name, + absl::string_view salt, absl::string_view data_elements) = 0; }; } // namespace presence diff --git a/presence/implementation/credential_manager_impl.cc b/presence/implementation/credential_manager_impl.cc index ef47678d..4384fe50 100644 --- a/presence/implementation/credential_manager_impl.cc +++ b/presence/implementation/credential_manager_impl.cc @@ -19,21 +19,29 @@ #include #include +#include "absl/status/status.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "internal/crypto/aead.h" #include "internal/crypto/ec_private_key.h" #include "internal/crypto/hkdf.h" #include "internal/platform/base64_utils.h" +#include "internal/platform/future.h" +#include "internal/platform/implementation/credential_callbacks.h" #include "internal/platform/implementation/crypto.h" #include "internal/platform/logging.h" #include "internal/proto/credential.proto.h" #include "presence/implementation/encryption.h" +#include "presence/implementation/ldt.h" namespace nearby { namespace presence { namespace { using ::location::nearby::Base64Utils; using ::location::nearby::Crypto; +using ::location::nearby::Exception; +using ::location::nearby::ExceptionOr; +using ::location::nearby::Future; using ::nearby::internal::DeviceMetadata; using ::nearby::internal::IdentityType; using ::nearby::internal::PrivateCredential; @@ -42,6 +50,8 @@ using ::nearby::internal::PublicCredential; // Key to retrieve local device's Private/Public Key Credentials from key store. constexpr char kPairedKeyAliasPrefix[] = "nearby_presence_paired_key_alias_"; +constexpr absl::Duration kTimeout = absl::Seconds(3); + } // namespace void CredentialManagerImpl::GenerateCredentials( @@ -238,5 +248,51 @@ void CredentialManagerImpl::GetPublicCredentials( credential_selector, public_credential_type, std::move(callback)); } +ExceptionOr> +CredentialManagerImpl::GetPrivateCredentialsSync( + const CredentialSelector& credential_selector, absl::Duration timeout) { + Future> result; + GetPrivateCredentials( + credential_selector, + { + .credentials_fetched_cb = + [result](std::vector credentials) mutable { + result.Set(credentials); + }, + .get_credentials_failed_cb = + [result](CredentialOperationStatus status) mutable { + result.SetException({Exception::kFailed}); + }, + }); + return result.Get(timeout); +} + +absl::StatusOr CredentialManagerImpl::EncryptDataElements( + nearby::internal::IdentityType identity, absl::string_view account_name, + absl::string_view salt, absl::string_view data_elements) { + CredentialSelector selector = { + .manager_app_id = "", + .account_name = std::string(account_name), + .identity_type = identity, + }; + ExceptionOr> credentials = + GetPrivateCredentialsSync(selector, kTimeout); + if (!credentials.ok()) { + return absl::UnavailableError("Failed to fetch credentials"); + } + if (credentials.result().empty()) { + return absl::UnavailableError("No credentials"); + } + PrivateCredential& credential = credentials.result().front(); + + // HMAC is not used during encryption, so we can pass an empty value. + absl::StatusOr encryptor = + LdtEncryptor::Create(credential.authenticity_key(), /*known_hmac=*/""); + if (!encryptor.ok()) { + return encryptor.status(); + } + return encryptor->Encrypt(data_elements, salt); +} + } // namespace presence } // namespace nearby diff --git a/presence/implementation/credential_manager_impl.h b/presence/implementation/credential_manager_impl.h index 364ceb6f..83095790 100644 --- a/presence/implementation/credential_manager_impl.h +++ b/presence/implementation/credential_manager_impl.h @@ -70,6 +70,12 @@ class CredentialManagerImpl : public CredentialManager { const CredentialSelector& credential_selector, GetPrivateCredentialsResultCallback callback) override; + // Blocking version of `GetPrivateCredentials` + location::nearby::ExceptionOr< + std::vector> + GetPrivateCredentialsSync(const CredentialSelector& credential_selector, + absl::Duration timeout); + // Used to fetch remote public creds when scanning. void GetPublicCredentials( const CredentialSelector& credential_selector, @@ -87,10 +93,8 @@ class CredentialManagerImpl : public CredentialManager { } absl::StatusOr EncryptDataElements( - nearby::internal::IdentityType identity, absl::string_view salt, - absl::string_view data_elements) override { - return absl::UnimplementedError("EncryptDataElements unimplemented"); - } + nearby::internal::IdentityType identity, absl::string_view account_name, + absl::string_view salt, absl::string_view data_elements) override; std::pair diff --git a/presence/implementation/credential_manager_impl_test.cc b/presence/implementation/credential_manager_impl_test.cc index e00960e4..257bbfef 100644 --- a/presence/implementation/credential_manager_impl_test.cc +++ b/presence/implementation/credential_manager_impl_test.cc @@ -346,15 +346,29 @@ TEST(CredentialManagerImpl, PublicCredentialsFailEncryption) { EXPECT_TRUE(publicCredentials.empty()); } +TEST(CredentialManagerImpl, EncryptDataElements) { + absl::string_view salt = "AB"; + absl::string_view data_elements = "data_elements"; + DeviceMetadata device_metadata = CreateTestDeviceMetadata(); + CredentialManagerImpl credential_manager; + std::vector identity_types{IDENTITY_TYPE_PRIVATE}; + credential_manager.GenerateCredentials( + device_metadata, "", identity_types, 1, 1, + { + .credentials_generated_cb = + [](std::vector) {}, + }); + + EXPECT_THAT(credential_manager.EncryptDataElements( + IDENTITY_TYPE_PRIVATE, "test_account", salt, data_elements), + absl::Status(absl::StatusCode::kUnavailable, + "Failed to create LDT encryptor")); +} + TEST(CredentialManagerImpl, UnimplementedFunctions) { CredentialManagerImpl credential_manager; constexpr absl::string_view salt = "salt"; constexpr absl::string_view data_elements = "data_elements"; - IdentityType identity = IDENTITY_TYPE_PRIVATE; - EXPECT_THAT( - credential_manager.EncryptDataElements(identity, salt, data_elements), - absl::Status(absl::StatusCode::kUnimplemented, - "EncryptDataElements unimplemented")); EXPECT_THAT(credential_manager.DecryptDataElements(salt, data_elements), absl::Status(absl::StatusCode::kUnimplemented, "DecryptDataElements unimplemented")); diff --git a/presence/implementation/ldt.cc b/presence/implementation/ldt.cc new file mode 100644 index 00000000..68039b8a --- /dev/null +++ b/presence/implementation/ldt.cc @@ -0,0 +1,116 @@ +// 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 "presence/implementation/ldt.h" + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "presence/implementation/np_ldt.h" +#include + +namespace nearby { +namespace presence { + +namespace { +template +T FromStringView(absl::string_view data) { + T result{ + .bytes = {0}, + }; + memcpy(result.bytes, data.data(), + std::min(sizeof(result.bytes), data.size())); + return result; +} + +struct AesContext { + AES_KEY encryption_key; + AES_KEY decryption_key; +}; + +NpLdtAesCipherHandle AesCreateCipher(NpLdtAes128Key key) { + AesContext* ctx = new AesContext(); + AES_set_encrypt_key(key.bytes, 128, &ctx->encryption_key); + AES_set_decrypt_key(key.bytes, 128, &ctx->decryption_key); + // The caller takes ownership and they must call `AesCloseCipher` eventually. + return ctx; +} + +int32_t AesCloseCipher(NpLdtAesCipherHandle handle) { + AesContext* ctx = reinterpret_cast(handle); + free(ctx); + return 0; +} + +void AesEncrypt(NpLdtAesCipherHandle handle, NpLdtAesBlock* block) { + AesContext* ctx = reinterpret_cast(handle); + AES_encrypt(block->bytes, block->bytes, &ctx->encryption_key); +} + +void AesDecrypt(NpLdtAesCipherHandle handle, NpLdtAesBlock* block) { + AesContext* ctx = reinterpret_cast(handle); + AES_decrypt(block->bytes, block->bytes, &ctx->decryption_key); +} + +} // namespace + +absl::StatusOr LdtEncryptor::Create( + absl::string_view key_seed, absl::string_view known_hmac) { + NpLdtHandle handle = + NpLdtCreate({.create_cipher = AesCreateCipher, + .close_cipher = AesCloseCipher, + .encrypt = AesEncrypt, + .decrypt = AesDecrypt}, + FromStringView(key_seed), + FromStringView(known_hmac)); + if (handle == nullptr) { + return absl::UnavailableError("Failed to create LDT encryptor"); + } + + return LdtEncryptor(handle); +} + +absl::StatusOr LdtEncryptor::Encrypt(absl::string_view data, + absl::string_view salt) { + std::string encrypted = std::string(data); + NP_LDT_RESULT result = + NpLdtEncrypt(ldt_handle_, reinterpret_cast(encrypted.data()), + encrypted.size(), FromStringView(salt)); + if (result == NP_LDT_SUCCESS) { + return encrypted; + } + return absl::InternalError( + absl::StrFormat("LDT encryption failed, errorcode %d", result)); +} + +absl::StatusOr LdtEncryptor::DecryptAndVerify( + absl::string_view data, absl::string_view salt) { + std::string encrypted = std::string(data); + NP_LDT_RESULT result = NpLdtDecryptAndVerify( + ldt_handle_, reinterpret_cast(encrypted.data()), + encrypted.size(), FromStringView(salt)); + if (result == NP_LDT_SUCCESS) { + return encrypted; + } + return absl::InternalError( + absl::StrFormat("LDT encryption failed, errorcode %d", result)); +} + +} // namespace presence +} // namespace nearby diff --git a/presence/implementation/ldt.h b/presence/implementation/ldt.h new file mode 100644 index 00000000..22ab45a3 --- /dev/null +++ b/presence/implementation/ldt.h @@ -0,0 +1,72 @@ +// 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. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "presence/implementation/np_ldt.h" + +namespace nearby { +namespace presence { + +// C++ abstraction on top of LDT C API. +class LdtEncryptor { + public: + LdtEncryptor(const LdtEncryptor&) = delete; + LdtEncryptor(LdtEncryptor&& other) : ldt_handle_(other.ldt_handle_) { + other.ldt_handle_ = nullptr; + } + LdtEncryptor& operator=(const LdtEncryptor&) = delete; + LdtEncryptor& operator=(LdtEncryptor&& other) { + std::swap(ldt_handle_, other.ldt_handle_); + return *this; + } + ~LdtEncryptor() { + if (ldt_handle_ != nullptr) { + NpLdtClose(ldt_handle_); + } + } + + // Creates an instance of `LdtEncryptor`. + // `key_seed` is used to generate LDT encryption and decryption keys. + // `known_hmac` is used during decryption to verify if the message was + // encrypted with the expected key. + static absl::StatusOr Create(absl::string_view key_seed, + absl::string_view known_hmac); + + // Encrypts `data`, which must be 16 - 31 bytes long. + absl::StatusOr Encrypt(absl::string_view data, + absl::string_view salt); + + // Decrypts `data` and verifies if it was encrypted with a key generated from + // `key_seed`. + absl::StatusOr DecryptAndVerify(absl::string_view data, + absl::string_view salt); + + private: + explicit LdtEncryptor(NpLdtHandle ldt_handle) : ldt_handle_(ldt_handle) {} + // An opaque handle to the underlying LDT implementation. It can be null iff + // this object has already been destroyed. + NpLdtHandle ldt_handle_; +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ diff --git a/presence/implementation/np_ldt.c b/presence/implementation/np_ldt.c new file mode 100644 index 00000000..f8c24263 --- /dev/null +++ b/presence/implementation/np_ldt.c @@ -0,0 +1,35 @@ +// 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/np_ldt.h" + +// Placeholder, empty implementations of LDT utilities. They will be replaced +// with implementations in Rust. + +NpLdtHandle NpLdtCreate(NpLdtAesConfig aes_config, NpLdtKeySeed key_seed, + NpMetadataKeyHmac known_hmac) { + return 0; +} + +NP_LDT_RESULT NpLdtClose(NpLdtHandle handle) { return NP_LDT_SUCCESS; } + +NP_LDT_RESULT NpLdtEncrypt(NpLdtHandle handle, uint8_t* buffer, + size_t buffer_len, NpLdtSalt salt) { + return NP_LDT_SUCCESS; +} + +NP_LDT_RESULT NpLdtDecryptAndVerify(NpLdtHandle handle, uint8_t* buffer, + size_t buffer_len, NpLdtSalt salt) { + return NP_LDT_SUCCESS; +}