mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
Add initial pairing in scalable seeker
PiperOrigin-RevId: 541034178
This commit is contained in:
committed by
Copybara-Service
parent
4914cbc2f9
commit
20acd4eeb9
@@ -55,6 +55,7 @@ cc_library(
|
||||
"//fastpair:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":fake_gatt_callbacks",
|
||||
":message_stream",
|
||||
"//fastpair/common",
|
||||
"//internal/platform:base",
|
||||
@@ -87,6 +88,7 @@ cc_library(
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "internal/platform/ble_v2.h"
|
||||
#include "internal/platform/future.h"
|
||||
|
||||
@@ -43,14 +44,22 @@ class FakeGattCallbacks {
|
||||
// characteristic
|
||||
absl::StatusOr<std::string> read_value =
|
||||
absl::FailedPreconditionError("characteristic not set");
|
||||
absl::AnyInvocable<absl::Status(absl::string_view)> write_callback =
|
||||
[&](absl::string_view data) {
|
||||
write_value.Set(std::string(data));
|
||||
return write_result;
|
||||
};
|
||||
absl::AnyInvocable<absl::StatusOr<std::string>()> read_callback = [&]() {
|
||||
absl::AnyInvocable<absl::Status(absl::string_view)> write_callback;
|
||||
absl::AnyInvocable<absl::StatusOr<std::string>()> read_callback;
|
||||
|
||||
absl::Status WriteCallback(absl::string_view data) {
|
||||
if (write_callback) {
|
||||
return write_callback(data);
|
||||
}
|
||||
write_value.Set(std::string(data));
|
||||
return write_result;
|
||||
}
|
||||
absl::StatusOr<std::string> ReadCallback() {
|
||||
if (read_callback) {
|
||||
return read_callback();
|
||||
}
|
||||
return read_value;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
BleV2Medium::ServerGattConnectionCallback GetGattCallback() {
|
||||
@@ -65,7 +74,7 @@ class FakeGattCallbacks {
|
||||
callback(absl::NotFoundError("characteristic not found"));
|
||||
return;
|
||||
}
|
||||
callback(it->second.read_callback());
|
||||
callback(it->second.ReadCallback());
|
||||
},
|
||||
.on_characteristic_write_cb =
|
||||
[&](const api::ble_v2::BlePeripheral& remote_device,
|
||||
@@ -78,7 +87,7 @@ class FakeGattCallbacks {
|
||||
callback(absl::NotFoundError("characteristic not found"));
|
||||
return;
|
||||
}
|
||||
callback(it->second.write_callback(data));
|
||||
callback(it->second.WriteCallback(data));
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
#include <openssl/base.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec_key.h>
|
||||
@@ -28,6 +30,10 @@ namespace fastpair {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint8_t kKeyBasedPairingResponseCode = 1;
|
||||
constexpr uint8_t kSeekerPasskeyResponseCode = 2;
|
||||
constexpr uint8_t kProviderPasskeyResponseCode = 3;
|
||||
|
||||
static EC_POINT *load_public_key(absl::string_view public_key) {
|
||||
CHECK_EQ(public_key.size(), kPublicKeyByteSize);
|
||||
BN_CTX *bn_ctx;
|
||||
@@ -129,22 +135,22 @@ void FakeProvider::LoadAntiSpoofingKey(absl::string_view private_key,
|
||||
}
|
||||
|
||||
std::string FakeProvider::DecryptKbpRequest(absl::string_view request) {
|
||||
NEARBY_LOGS(INFO) << "Encrypted KBP request "
|
||||
<< absl::BytesToHexString(request);
|
||||
NEARBY_LOGS(VERBOSE) << "Encrypted KBP request "
|
||||
<< absl::BytesToHexString(request);
|
||||
CHECK_EQ(request.size(), kEncryptedDataByteSize + kPublicKeyByteSize);
|
||||
absl::string_view encrypted = request.substr(0, kEncryptedDataByteSize);
|
||||
absl::string_view remote_public_key =
|
||||
request.substr(kEncryptedDataByteSize, kPublicKeyByteSize);
|
||||
std::string shared_secret = CreateSharedSecret(remote_public_key);
|
||||
std::string decrypted = Aes128Decrypt(encrypted, shared_secret);
|
||||
NEARBY_LOGS(INFO) << "Decrypted KBP request "
|
||||
<< absl::BytesToHexString(decrypted);
|
||||
account_key_ = shared_secret;
|
||||
NEARBY_LOGS(VERBOSE) << "Decrypted KBP request "
|
||||
<< absl::BytesToHexString(decrypted);
|
||||
shared_secret_ = shared_secret;
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
std::string FakeProvider::Encrypt(absl::string_view data) {
|
||||
return Aes128Encrypt(data, account_key_);
|
||||
return Aes128Encrypt(data, shared_secret_);
|
||||
}
|
||||
|
||||
std::string FakeProvider::GenSec256r1Secret(
|
||||
@@ -199,9 +205,9 @@ std::string FakeProvider::CreateSharedSecret(
|
||||
Crypto::Sha256(secret).AsStringView().substr(0, kAccountKeySize));
|
||||
}
|
||||
|
||||
void FakeProvider::StartGattServer(
|
||||
BleV2Medium::ServerGattConnectionCallback callback) {
|
||||
gatt_server_ = ble_.StartGattServer(std::move(callback));
|
||||
void FakeProvider::StartGattServer(FakeGattCallbacks *fake_gatt_callbacks) {
|
||||
fake_gatt_callbacks_ = fake_gatt_callbacks;
|
||||
gatt_server_ = ble_.StartGattServer(fake_gatt_callbacks_->GetGattCallback());
|
||||
}
|
||||
|
||||
absl::Status FakeProvider::NotifyKeyBasedPairing(ByteArray response) {
|
||||
@@ -211,8 +217,16 @@ absl::Status FakeProvider::NotifyKeyBasedPairing(ByteArray response) {
|
||||
false, response);
|
||||
}
|
||||
|
||||
absl::Status FakeProvider::NotifyPasskey(ByteArray response) {
|
||||
CHECK_NE(gatt_server_, nullptr);
|
||||
CHECK(passkey_characteristic_.has_value());
|
||||
return gatt_server_->NotifyCharacteristicChanged(*passkey_characteristic_,
|
||||
false, response);
|
||||
}
|
||||
|
||||
void FakeProvider::StartDiscoverableAdvertisement(absl::string_view model_id) {
|
||||
advertising_ = true;
|
||||
model_id_ = model_id;
|
||||
ble_v1_.StartAdvertising(std::string(kServiceID),
|
||||
ByteArray(absl::HexStringToBytes(model_id)),
|
||||
std::string(kFastPairServiceUuid));
|
||||
@@ -225,5 +239,101 @@ void FakeProvider::StopAdvertising() {
|
||||
}
|
||||
}
|
||||
|
||||
void FakeProvider::SetKeyBasedPairingCallback() {
|
||||
CHECK_NE(fake_gatt_callbacks_, nullptr);
|
||||
CHECK(key_based_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
|
||||
.write_callback = [this](absl::string_view request) {
|
||||
NEARBY_LOGS(VERBOSE) << "Encrypted request: "
|
||||
<< absl::BytesToHexString(request);
|
||||
std::string decrypted_request = DecryptKbpRequest(request);
|
||||
NEARBY_LOGS(VERBOSE) << "KBP decrypted request "
|
||||
<< absl::BytesToHexString(decrypted_request);
|
||||
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
|
||||
.write_value.Set(std::string(decrypted_request));
|
||||
std::string response;
|
||||
response.push_back(kKeyBasedPairingResponseCode);
|
||||
response.append(GetMacAddressAsBytes());
|
||||
response.resize(kEncryptedDataByteSize, 0);
|
||||
absl::Status status = NotifyKeyBasedPairing(ByteArray(Encrypt(response)));
|
||||
NEARBY_LOGS(VERBOSE) << "KBP notify result: " << status;
|
||||
return absl::OkStatus();
|
||||
};
|
||||
}
|
||||
|
||||
void FakeProvider::SetPasskeyCallback() {
|
||||
CHECK_NE(fake_gatt_callbacks_, nullptr);
|
||||
CHECK(passkey_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
|
||||
.write_callback = [this](absl::string_view request) {
|
||||
NEARBY_LOGS(VERBOSE) << "Passkey Encrypted request: "
|
||||
<< absl::BytesToHexString(request);
|
||||
std::string decrypted = Aes128Decrypt(request, shared_secret_);
|
||||
NEARBY_LOGS(VERBOSE) << "Passkey decrypted request "
|
||||
<< absl::BytesToHexString(decrypted);
|
||||
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
|
||||
.write_value.Set(std::string(decrypted));
|
||||
if (decrypted[0] != kSeekerPasskeyResponseCode) {
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrFormat("Invalid passkey response code: 0x%x", decrypted[0]));
|
||||
}
|
||||
|
||||
std::string response;
|
||||
response.push_back(kProviderPasskeyResponseCode);
|
||||
response.push_back(pass_key_ >> 16);
|
||||
response.push_back(pass_key_ >> 8);
|
||||
response.push_back(pass_key_);
|
||||
response.resize(kEncryptedDataByteSize, 0);
|
||||
absl::Status status = NotifyPasskey(ByteArray(Encrypt(response)));
|
||||
NEARBY_LOGS(VERBOSE) << "Passkey notify result: " << status;
|
||||
return absl::OkStatus();
|
||||
};
|
||||
}
|
||||
|
||||
void FakeProvider::SetAccountkeyCallback() {
|
||||
CHECK_NE(fake_gatt_callbacks_, nullptr);
|
||||
CHECK(accountkey_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
|
||||
.write_callback = [this](absl::string_view request) {
|
||||
NEARBY_LOGS(VERBOSE) << "Account key encrypted request: "
|
||||
<< absl::BytesToHexString(request);
|
||||
std::string decrypted = Aes128Decrypt(request, shared_secret_);
|
||||
NEARBY_LOGS(VERBOSE) << "Account key decrypted request "
|
||||
<< absl::BytesToHexString(decrypted);
|
||||
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
|
||||
.write_value.Set(std::string(decrypted));
|
||||
|
||||
account_key_ = AccountKey(decrypted);
|
||||
return absl::OkStatus();
|
||||
};
|
||||
}
|
||||
|
||||
void FakeProvider::ConfigurePairingContext(absl::string_view pass_key) {
|
||||
api::PairingParams pairing_params;
|
||||
pairing_params.pairing_type =
|
||||
api::PairingParams::PairingType::kConfirmPasskey;
|
||||
pairing_params.passkey = pass_key;
|
||||
auto device = MediumEnvironment::Instance().FindBluetoothDevice(
|
||||
provider_medium_.GetMacAddress());
|
||||
CHECK_NE(device, nullptr);
|
||||
MediumEnvironment::Instance().ConfigBluetoothPairingContext(device,
|
||||
pairing_params);
|
||||
CHECK(absl::SimpleAtoi(pass_key, &pass_key_));
|
||||
}
|
||||
|
||||
void FakeProvider::PrepareForInitialPairing(
|
||||
PairingConfig config, FakeGattCallbacks *fake_gatt_callbacks) {
|
||||
LoadAntiSpoofingKey(config.private_key, config.public_key);
|
||||
StartGattServer(fake_gatt_callbacks);
|
||||
InsertCorrectGattCharacteristics();
|
||||
SetKeyBasedPairingCallback();
|
||||
SetPasskeyCallback();
|
||||
SetAccountkeyCallback();
|
||||
provider_adapter_.SetScanMode(
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
|
||||
ConfigurePairingContext(config.pass_key);
|
||||
StartDiscoverableAdvertisement(config.model_id);
|
||||
}
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "fastpair/common/account_key.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/common/fast_pair_device.h"
|
||||
#include "fastpair/message_stream/fake_gatt_callbacks.h"
|
||||
#include "fastpair/message_stream/message.h"
|
||||
#include "internal/platform/ble.h"
|
||||
#include "internal/platform/ble_v2.h"
|
||||
@@ -71,8 +73,18 @@ class FakeProvider {
|
||||
public:
|
||||
using KeyBasedPairingCallback =
|
||||
absl::AnyInvocable<std::string(absl::string_view)>;
|
||||
struct PairingConfig {
|
||||
std::string private_key; // binary, private Anti-Spoofing Key
|
||||
std::string public_key; // binary, public Anti-Spoofing Key
|
||||
std::string model_id;
|
||||
std::string pass_key;
|
||||
};
|
||||
~FakeProvider() { Shutdown(); }
|
||||
|
||||
// Sets the fake provider up for initial pairing
|
||||
void PrepareForInitialPairing(PairingConfig config,
|
||||
FakeGattCallbacks* fake_gatt_callbacks);
|
||||
|
||||
void Shutdown() {
|
||||
StopAdvertising();
|
||||
provider_thread_.Shutdown();
|
||||
@@ -151,25 +163,31 @@ class FakeProvider {
|
||||
BluetoothUtils::FromString(provider_adapter_.GetMacAddress()));
|
||||
}
|
||||
|
||||
void StartGattServer(BleV2Medium::ServerGattConnectionCallback callback);
|
||||
void StartGattServer(FakeGattCallbacks* fake_gatt_callbacks);
|
||||
|
||||
void InsertCorrectGattCharacteristics() {
|
||||
CHECK_NE(fake_gatt_callbacks_, nullptr);
|
||||
|
||||
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
|
||||
kFastPairServiceUuid, kKeyBasedCharacteristicUuidV2, permissions_,
|
||||
properties_);
|
||||
CHECK(key_based_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*key_based_characteristic_]
|
||||
.write_result = absl::OkStatus();
|
||||
|
||||
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
|
||||
kFastPairServiceUuid, kPasskeyCharacteristicUuidV2, permissions_,
|
||||
properties_);
|
||||
|
||||
CHECK(passkey_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*passkey_characteristic_]
|
||||
.write_result = absl::OkStatus();
|
||||
|
||||
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
|
||||
kFastPairServiceUuid, kAccountKeyCharacteristicUuidV2, permissions_,
|
||||
properties_);
|
||||
|
||||
CHECK(accountkey_characteristic_.has_value());
|
||||
fake_gatt_callbacks_->characteristics_[*accountkey_characteristic_]
|
||||
.write_result = absl::OkStatus();
|
||||
}
|
||||
|
||||
void LoadAntiSpoofingKey(absl::string_view private_key,
|
||||
@@ -179,14 +197,20 @@ class FakeProvider {
|
||||
std::string Encrypt(absl::string_view data);
|
||||
|
||||
absl::Status NotifyKeyBasedPairing(ByteArray response);
|
||||
absl::Status NotifyPasskey(ByteArray response);
|
||||
|
||||
void StartDiscoverableAdvertisement(absl::string_view model_id);
|
||||
void StopAdvertising();
|
||||
void ConfigurePairingContext(absl::string_view pass_key);
|
||||
AccountKey& GetAccountKey() { return account_key_; }
|
||||
std::optional<GattCharacteristic> key_based_characteristic_;
|
||||
std::optional<GattCharacteristic> passkey_characteristic_;
|
||||
std::optional<GattCharacteristic> accountkey_characteristic_;
|
||||
|
||||
private:
|
||||
void SetKeyBasedPairingCallback();
|
||||
void SetPasskeyCallback();
|
||||
void SetAccountkeyCallback();
|
||||
std::string GenSec256r1Secret(absl::string_view remote_party_public_key);
|
||||
std::string CreateSharedSecret(absl::string_view remote_public_key);
|
||||
BluetoothAdapter provider_adapter_;
|
||||
@@ -201,8 +225,12 @@ class FakeProvider {
|
||||
Permission permissions_ = Permission::kWrite;
|
||||
std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY*)> anti_spoofing_key_{
|
||||
nullptr, EVP_PKEY_free};
|
||||
std::string account_key_;
|
||||
std::string shared_secret_;
|
||||
SingleThreadExecutor provider_thread_;
|
||||
std::string model_id_;
|
||||
FakeGattCallbacks* fake_gatt_callbacks_ = nullptr;
|
||||
unsigned int pass_key_;
|
||||
AccountKey account_key_;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
|
||||
Reference in New Issue
Block a user