mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
Implement ECDH and AES Encryption/ Decryption for Fast Pair Windows
PiperOrigin-RevId: 501666600
This commit is contained in:
committed by
Copybara-Service
parent
bde4a780c6
commit
7eeea7a283
@@ -15,9 +15,12 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_COMMON_CONSTANT_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_COMMON_CONSTANT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Bluetooth Uuid
|
||||
constexpr char kServiceId[] = "Fast Pair";
|
||||
constexpr char kFastPairServiceUuid[] = "0000FE2C-0000-1000-8000-00805F9B34FB";
|
||||
const char kKeyBasedPairingCharacteristicUuidV1[] = "1234";
|
||||
@@ -30,6 +33,44 @@ const char kAccountKeyCharacteristicUuidV1[] = "1236";
|
||||
const char kAccountKeyCharacteristicUuidV2[] =
|
||||
"FE2C1236-8366-4814-8EB0-01DE32100BEA";
|
||||
|
||||
// Key pair
|
||||
constexpr int kSharedSecretKeyByteSize = 16;
|
||||
constexpr int kPublicKeyByteSize = 64;
|
||||
|
||||
// Encryption
|
||||
constexpr int kAesBlockByteSize = 16;
|
||||
constexpr int kEncryptedDataByteSize = 16;
|
||||
// Decryption
|
||||
constexpr int kDecryptedResponseAddressByteSize = 6;
|
||||
constexpr int kDecryptedResponseSaltByteSize = 9;
|
||||
constexpr int kDecryptedPasskeySaltByteSize = 12;
|
||||
|
||||
// Handshake response index
|
||||
constexpr int kMessageTypeIndex = 0;
|
||||
constexpr int kResponseAddressStartIndex = 1;
|
||||
constexpr int kResponseSaltStartIndex = 7;
|
||||
constexpr int kPasskeySaltStartIndex = 4;
|
||||
|
||||
// Handshake response message type
|
||||
constexpr uint8_t kKeybasedPairingResponseType = 0x01;
|
||||
constexpr uint8_t kSeekerPasskeyType = 0x02;
|
||||
constexpr uint8_t kProviderPasskeyType = 0x03;
|
||||
|
||||
// Handshake request inex
|
||||
constexpr uint8_t kProviderAddressStartIndex = 2;
|
||||
constexpr uint8_t kSeekerAddressStartIndex = 8;
|
||||
constexpr uint8_t kSeekerPasskey = 0x02;
|
||||
constexpr uint8_t kAccountKeyStartByte = 0x04;
|
||||
|
||||
// Handshake request message type
|
||||
constexpr uint8_t kKeyBasedPairingType = 0x00;
|
||||
constexpr uint8_t kInitialOrSubsequentFlags = 0x00;
|
||||
constexpr uint8_t kRetroactiveFlags = 0x10;
|
||||
|
||||
// GATT connection
|
||||
constexpr int kMaxNumGattConnectionAttempts = 3;
|
||||
constexpr int kGattOperationTimeout = 15;
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# 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.
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "handshake",
|
||||
srcs = [
|
||||
"fast_pair_decryption.cc",
|
||||
"fast_pair_encryption.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"decrypted_passkey.h",
|
||||
"decrypted_response.h",
|
||||
"fast_pair_decryption.h",
|
||||
"fast_pair_encryption.h",
|
||||
"fast_pair_key_pair.h",
|
||||
"fast_pair_message_type.h",
|
||||
],
|
||||
visibility = [
|
||||
"//:__subpackages__",
|
||||
"//fastpair:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//fastpair/common",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
"@boringssl//:crypto",
|
||||
"@com_google_absl//absl/log:check",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "decrypted_passkey_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"decrypted_passkey_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":handshake",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "decrypted_response_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"decrypted_response_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":handshake",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fast_pair_key_pair_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"fast_pair_key_pair_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":handshake",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fast_pair_encryption_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"fast_pair_encryption_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":handshake",
|
||||
"//fastpair/common",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fast_pair_decryption_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"fast_pair_decryption_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":handshake",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_DECRYPTED_PASSKEY_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_DECRYPTED_PASSKEY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/handshake/fast_pair_message_type.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Thin structure which is used by the higher level components of the Fast Pair
|
||||
// system to represent a decrypted account passkey.
|
||||
struct DecryptedPasskey {
|
||||
DecryptedPasskey(
|
||||
FastPairMessageType message_type, uint32_t passkey,
|
||||
const std::array<uint8_t, kDecryptedPasskeySaltByteSize>& salt)
|
||||
: message_type(message_type), passkey(passkey), salt(salt) {}
|
||||
|
||||
FastPairMessageType message_type;
|
||||
uint32_t passkey;
|
||||
std::array<uint8_t, kDecryptedPasskeySaltByteSize> salt;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_DECRYPTED_PASSKEY_H_
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 "fastpair/handshake/decrypted_passkey.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
TEST(DecryptedPasskeyTest, CreateDecryptedPasskey) {
|
||||
// Message type
|
||||
FastPairMessageType messgaeType = FastPairMessageType::kSeekersPasskey;
|
||||
// Passkey bytes.
|
||||
std::array<uint8_t, 3> passkey_bytes = {0x02, 0x03, 0x04};
|
||||
uint32_t passkey = passkey_bytes[2];
|
||||
passkey += passkey_bytes[1] << 8;
|
||||
passkey += passkey_bytes[0] << 16;
|
||||
|
||||
// Random salt
|
||||
std::array<uint8_t, 12> salt = {0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E,
|
||||
0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
|
||||
|
||||
DecryptedPasskey decryptedPasskey(messgaeType, passkey, salt);
|
||||
EXPECT_EQ(decryptedPasskey.message_type, messgaeType);
|
||||
EXPECT_EQ(decryptedPasskey.passkey, passkey);
|
||||
EXPECT_EQ(decryptedPasskey.salt, salt);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_DECRYPTED_RESPONSE_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_DECRYPTED_RESPONSE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/handshake/fast_pair_message_type.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Thin structure which is used by the higher level components of the Fast Pair
|
||||
// system to represent a decrypted response.
|
||||
struct DecryptedResponse {
|
||||
DecryptedResponse(
|
||||
FastPairMessageType message_type,
|
||||
const std::array<uint8_t, kDecryptedResponseAddressByteSize>&
|
||||
address_bytes,
|
||||
const std::array<uint8_t, kDecryptedResponseSaltByteSize>& salt)
|
||||
: message_type(message_type), address_bytes(address_bytes), salt(salt) {}
|
||||
|
||||
FastPairMessageType message_type;
|
||||
std::array<uint8_t, kDecryptedResponseAddressByteSize> address_bytes;
|
||||
std::array<uint8_t, kDecryptedResponseSaltByteSize> salt;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_DECRYPTED_RESPONSE_H_
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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 "fastpair/handshake/decrypted_response.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
TEST(DecryptedResponseTest, CreateDecryptedResponse) {
|
||||
constexpr std::array<uint8_t, 6> address_bytes = {0x02, 0x03, 0x04,
|
||||
0x05, 0x06, 0x07};
|
||||
|
||||
constexpr std::array<uint8_t, 9> salt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x00};
|
||||
|
||||
DecryptedResponse decryptedResponse(
|
||||
FastPairMessageType::kKeyBasedPairingResponse, address_bytes, salt);
|
||||
EXPECT_EQ(decryptedResponse.message_type,
|
||||
FastPairMessageType::kKeyBasedPairingResponse);
|
||||
EXPECT_EQ(decryptedResponse.address_bytes, address_bytes);
|
||||
EXPECT_EQ(decryptedResponse.salt, salt);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,115 @@
|
||||
// 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 "fastpair/handshake/fast_pair_decryption.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#ifdef NEARBY_CHROMIUM
|
||||
#include "base/check.h"
|
||||
#elif defined(NEARBY_SWIFTPM)
|
||||
#include "internal/platform/logging.h"
|
||||
#else
|
||||
#include "absl/log/check.h" // nogncheck
|
||||
#endif
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/handshake/decrypted_passkey.h"
|
||||
#include "fastpair/handshake/decrypted_response.h"
|
||||
#include <openssl/aes.h>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
std::array<uint8_t, kAesBlockByteSize> FastPairDecryption::DecryptBytes(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& encrypted_bytes) {
|
||||
AES_KEY aes_key;
|
||||
int aes_key_was_set = AES_set_decrypt_key(aes_key_bytes.data(),
|
||||
aes_key_bytes.size() * 8, &aes_key);
|
||||
CHECK(aes_key_was_set == 0) << "Invalid AES key size.";
|
||||
std::array<uint8_t, kAesBlockByteSize> decrypted_bytes;
|
||||
// Encrypted_bytes is less than 16 bytes and can be guaranteed to be a
|
||||
// single block, so we encrypt/decrypt it using AES ECB mode
|
||||
// (Approved by: b/73360609)
|
||||
AES_decrypt(encrypted_bytes.data(), decrypted_bytes.data(), &aes_key);
|
||||
return decrypted_bytes;
|
||||
}
|
||||
|
||||
// Decrypts the encrypted response
|
||||
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.4)
|
||||
// and returns the parsed decrypted response
|
||||
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.3)
|
||||
absl::optional<DecryptedResponse> FastPairDecryption::ParseDecryptResponse(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& encrypted_response_bytes) {
|
||||
std::array<uint8_t, kAesBlockByteSize> decrypted_response_bytes =
|
||||
DecryptBytes(aes_key_bytes, encrypted_response_bytes);
|
||||
|
||||
uint8_t message_type = decrypted_response_bytes[kMessageTypeIndex];
|
||||
|
||||
// If the message type index is not the expected fast pair message type, then
|
||||
// this is not a valid fast pair response.
|
||||
if (message_type != kKeybasedPairingResponseType) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
std::array<uint8_t, kDecryptedResponseAddressByteSize> address_bytes;
|
||||
std::copy(decrypted_response_bytes.begin() + kResponseAddressStartIndex,
|
||||
decrypted_response_bytes.begin() + kResponseSaltStartIndex,
|
||||
address_bytes.begin());
|
||||
|
||||
std::array<uint8_t, kDecryptedResponseSaltByteSize> salt;
|
||||
std::copy(decrypted_response_bytes.begin() + kResponseSaltStartIndex,
|
||||
decrypted_response_bytes.end(), salt.begin());
|
||||
return DecryptedResponse(FastPairMessageType::kKeyBasedPairingResponse,
|
||||
address_bytes, salt);
|
||||
}
|
||||
|
||||
// Decrypts the encrypted passkey
|
||||
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table2.1)
|
||||
// and returns the parsed decrypted passkey
|
||||
// (https://developers.google.com/nearby/fast-pair/specifications/characteristics#table2.2)
|
||||
// TODO(b/263400788) Add unit test to cover this function and fix all Mutants
|
||||
// warning
|
||||
absl::optional<DecryptedPasskey> FastPairDecryption::ParseDecryptPasskey(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& encrypted_passkey_bytes) {
|
||||
std::array<uint8_t, kAesBlockByteSize> decrypted_passkey_bytes =
|
||||
DecryptBytes(aes_key_bytes, encrypted_passkey_bytes);
|
||||
|
||||
FastPairMessageType message_type;
|
||||
if (decrypted_passkey_bytes[kMessageTypeIndex] == kSeekerPasskeyType) {
|
||||
message_type = FastPairMessageType::kSeekersPasskey;
|
||||
} else if (decrypted_passkey_bytes[kMessageTypeIndex] ==
|
||||
kProviderPasskeyType) {
|
||||
message_type = FastPairMessageType::kProvidersPasskey;
|
||||
} else {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
uint32_t passkey = decrypted_passkey_bytes[3];
|
||||
passkey += decrypted_passkey_bytes[2] << 8;
|
||||
passkey += decrypted_passkey_bytes[1] << 16;
|
||||
|
||||
std::array<uint8_t, kDecryptedPasskeySaltByteSize> salt;
|
||||
std::copy(decrypted_passkey_bytes.begin() + kPasskeySaltStartIndex,
|
||||
decrypted_passkey_bytes.end(), salt.begin());
|
||||
return DecryptedPasskey(message_type, passkey, salt);
|
||||
}
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_FAST_PAIR_DECRYPTION_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DECRYPTION_H_
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "fastpair/handshake/decrypted_passkey.h"
|
||||
#include "fastpair/handshake/decrypted_response.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
/** Utilities used for encrypting and decrypting Fast Pair packets. */
|
||||
class FastPairDecryption {
|
||||
public:
|
||||
static constexpr int kAesBlockByteSize = 16;
|
||||
|
||||
static std::array<uint8_t, kAesBlockByteSize> DecryptBytes(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& encrypted_bytes);
|
||||
|
||||
static absl::optional<DecryptedResponse> ParseDecryptResponse(
|
||||
const std::array<uint8_t, 16>& aes_key_bytes,
|
||||
const std::array<uint8_t, 16>& encrypted_response_bytes);
|
||||
|
||||
static absl::optional<DecryptedPasskey> ParseDecryptPasskey(
|
||||
const std::array<uint8_t, 16>& aes_key_bytes,
|
||||
const std::array<uint8_t, 16>& encrypted_passkey_bytes);
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_DECRYPTION_H_
|
||||
@@ -0,0 +1,157 @@
|
||||
// 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 "fastpair/handshake/fast_pair_decryption.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "fastpair/handshake/fast_pair_encryption.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
// All test data comes from
|
||||
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
|
||||
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> aes_key_bytes = {
|
||||
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6,
|
||||
0xCF, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
|
||||
|
||||
TEST(FastPairDecryptionTest, ParseDecryptResponseSuccess) {
|
||||
std::vector<uint8_t> response_bytes;
|
||||
|
||||
// Message type.
|
||||
response_bytes.push_back(0x01);
|
||||
|
||||
// Address bytes.
|
||||
std::array<uint8_t, 6> address_bytes = {0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
|
||||
std::copy(address_bytes.begin(), address_bytes.end(),
|
||||
std::back_inserter(response_bytes));
|
||||
|
||||
// Random salt
|
||||
std::array<uint8_t, 9> salt = {0x08, 0x09, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x00};
|
||||
std::copy(salt.begin(), salt.end(), std::back_inserter(response_bytes));
|
||||
|
||||
std::array<uint8_t, kAesBlockByteSize> response_bytes_array;
|
||||
std::copy_n(response_bytes.begin(), kAesBlockByteSize,
|
||||
response_bytes_array.begin());
|
||||
|
||||
auto encrypted_bytes =
|
||||
FastPairEncryption::EncryptBytes(aes_key_bytes, response_bytes_array);
|
||||
auto response =
|
||||
FastPairDecryption::ParseDecryptResponse(aes_key_bytes, encrypted_bytes);
|
||||
|
||||
EXPECT_TRUE(response.has_value());
|
||||
EXPECT_EQ(response->message_type,
|
||||
FastPairMessageType::kKeyBasedPairingResponse);
|
||||
EXPECT_EQ(response->address_bytes, address_bytes);
|
||||
EXPECT_EQ(response->salt, salt);
|
||||
}
|
||||
|
||||
TEST(FastPairDecryptionTest, ParseDecryptResponseFailure) {
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> response_bytes = {
|
||||
/*message_type=*/0x02,
|
||||
/*address_bytes=*/0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
/*salt=*/0x08,
|
||||
0x09,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x00};
|
||||
|
||||
auto encrypted_bytes =
|
||||
FastPairEncryption::EncryptBytes(aes_key_bytes, response_bytes);
|
||||
auto response =
|
||||
FastPairDecryption::ParseDecryptResponse(aes_key_bytes, encrypted_bytes);
|
||||
|
||||
EXPECT_FALSE(response.has_value());
|
||||
}
|
||||
|
||||
TEST(FastPairDecryptionTest, ParseDecryptPasskeySuccess) {
|
||||
std::vector<uint8_t> passkey_bytes;
|
||||
|
||||
// Message type.
|
||||
passkey_bytes.push_back(0x02);
|
||||
|
||||
// Passkey bytes.
|
||||
uint32_t passkey = 5;
|
||||
passkey_bytes.push_back(passkey >> 16);
|
||||
passkey_bytes.push_back(passkey >> 8);
|
||||
passkey_bytes.push_back(passkey);
|
||||
|
||||
// Random salt
|
||||
std::array<uint8_t, 12> salt = {0x08, 0x09, 0x0A, 0x08, 0x09, 0x0E,
|
||||
0x0A, 0x0C, 0x0D, 0x0E, 0x05, 0x02};
|
||||
std::copy(salt.begin(), salt.end(), std::back_inserter(passkey_bytes));
|
||||
|
||||
std::array<uint8_t, kAesBlockByteSize> passkey_bytes_array;
|
||||
std::copy_n(passkey_bytes.begin(), kAesBlockByteSize,
|
||||
passkey_bytes_array.begin());
|
||||
|
||||
auto encrypted_bytes =
|
||||
FastPairEncryption::EncryptBytes(aes_key_bytes, passkey_bytes_array);
|
||||
auto decrypted_passkey =
|
||||
FastPairDecryption::ParseDecryptPasskey(aes_key_bytes, encrypted_bytes);
|
||||
|
||||
EXPECT_TRUE(decrypted_passkey.has_value());
|
||||
EXPECT_EQ(decrypted_passkey->message_type,
|
||||
FastPairMessageType::kSeekersPasskey);
|
||||
EXPECT_EQ(decrypted_passkey->passkey, passkey);
|
||||
EXPECT_EQ(decrypted_passkey->salt, salt);
|
||||
}
|
||||
|
||||
TEST(FastPairDecryptionTest, ParseDecryptPasskeyFailure) {
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> passkey_bytes = {
|
||||
/*message_type=*/0x04,
|
||||
/*passkey=*/0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
/*salt=*/0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x09,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x0E};
|
||||
|
||||
auto encrypted_bytes =
|
||||
FastPairEncryption::EncryptBytes(aes_key_bytes, passkey_bytes);
|
||||
auto passkey =
|
||||
FastPairDecryption::ParseDecryptPasskey(aes_key_bytes, encrypted_bytes);
|
||||
|
||||
EXPECT_FALSE(passkey.has_value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,165 @@
|
||||
// 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 "fastpair/handshake/fast_pair_encryption.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef NEARBY_CHROMIUM
|
||||
#include "base/check.h"
|
||||
#elif defined(NEARBY_SWIFTPM)
|
||||
#include "internal/platform/logging.h"
|
||||
#else
|
||||
#include "absl/log/check.h" // nogncheck
|
||||
#endif
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/handshake/fast_pair_key_pair.h"
|
||||
#include "fastpair/handshake/fast_pair_message_type.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/base.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/nid.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts the public anti-spoofing key into an EC_Point.
|
||||
bssl::UniquePtr<EC_POINT> GetEcPointFromPublicAntiSpoofingKey(
|
||||
const bssl::UniquePtr<EC_GROUP>& ec_group,
|
||||
std::string_view decoded_public_anti_spoofing) {
|
||||
std::array<uint8_t, kPublicKeyByteSize + 1> buffer;
|
||||
buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
|
||||
std::copy(decoded_public_anti_spoofing.begin(),
|
||||
decoded_public_anti_spoofing.end(), buffer.begin() + 1);
|
||||
|
||||
bssl::UniquePtr<EC_POINT> new_ec_point(EC_POINT_new(ec_group.get()));
|
||||
|
||||
if (!EC_POINT_oct2point(ec_group.get(), new_ec_point.get(), buffer.data(),
|
||||
buffer.size(), nullptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new_ec_point;
|
||||
}
|
||||
|
||||
// Key derivation function to be used in hashing the generated secret key.
|
||||
void* KDF(const void* in, size_t inlen, void* out, size_t* outlen) {
|
||||
// Set this to 16 since that's the amount of bytes we want to use
|
||||
// for the key, even though more will be written by SHA256 below.
|
||||
*outlen = kSharedSecretKeyByteSize;
|
||||
return SHA256(static_cast<const uint8_t*>(in), inlen,
|
||||
static_cast<uint8_t*>(out));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// TODO(b/263400788) Add unit test to cover this function and fix all Mutants
|
||||
// warning
|
||||
absl::optional<KeyPair> FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
|
||||
std::string_view decoded_public_anti_spoofing) {
|
||||
if (decoded_public_anti_spoofing.size() != kPublicKeyByteSize) {
|
||||
NEARBY_LOGS(VERBOSE) << "Expected " << kPublicKeyByteSize
|
||||
<< " byte value for anti-spoofing key. Got:"
|
||||
<< decoded_public_anti_spoofing.size();
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Generate the secp256r1 key-pair.
|
||||
bssl::UniquePtr<EC_GROUP> ec_group(
|
||||
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
bssl::UniquePtr<EC_KEY> ec_key(
|
||||
EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
|
||||
if (!EC_KEY_generate_key(ec_key.get())) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Failed to generate ec key";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// The ultimate goal here is to get a 64-byte public key. We accomplish this
|
||||
// by converting the generated public key into the uncompressed X9.62 format,
|
||||
// which is 0x04 followed by padded x and y coordinates.
|
||||
std::array<uint8_t, kPublicKeyByteSize + 1> uncompressed_private_key;
|
||||
int point_bytes_written = EC_POINT_point2oct(
|
||||
ec_group.get(), EC_KEY_get0_public_key(ec_key.get()),
|
||||
POINT_CONVERSION_UNCOMPRESSED, uncompressed_private_key.data(),
|
||||
uncompressed_private_key.size(), nullptr);
|
||||
|
||||
if (point_bytes_written != uncompressed_private_key.size()) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__
|
||||
<< ": EC_POINT_point2oct failed to convert public key "
|
||||
"to uncompressed x9.62 format.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<EC_POINT> public_anti_spoofing_point =
|
||||
GetEcPointFromPublicAntiSpoofingKey(ec_group,
|
||||
decoded_public_anti_spoofing);
|
||||
|
||||
if (!public_anti_spoofing_point) {
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __func__
|
||||
<< ": Failed to convert Public Anti-Spoofing key to EC_POINT";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
uint8_t secret[SHA256_DIGEST_LENGTH];
|
||||
int computed_key_size =
|
||||
ECDH_compute_key(secret, SHA256_DIGEST_LENGTH,
|
||||
public_anti_spoofing_point.get(), ec_key.get(), &KDF);
|
||||
|
||||
if (computed_key_size != kSharedSecretKeyByteSize) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": ECDH_compute_key failed.";
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Take first 16 bytes from secret as the shared secret key.
|
||||
std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key;
|
||||
std::copy(secret, secret + kSharedSecretKeyByteSize,
|
||||
std::begin(shared_secret_key));
|
||||
|
||||
// Ignore the first byte since it is 0x04, from the above uncompressed X9 .62
|
||||
// format.
|
||||
std::array<uint8_t, kPublicKeyByteSize> public_key;
|
||||
std::copy(uncompressed_private_key.begin() + 1,
|
||||
uncompressed_private_key.end(), public_key.begin());
|
||||
|
||||
return KeyPair(shared_secret_key, public_key);
|
||||
}
|
||||
|
||||
std::array<uint8_t, kAesBlockByteSize> FastPairEncryption::EncryptBytes(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt) {
|
||||
AES_KEY aes_key;
|
||||
int aes_key_was_set = AES_set_encrypt_key(aes_key_bytes.data(),
|
||||
aes_key_bytes.size() * 8, &aes_key);
|
||||
DCHECK(aes_key_was_set == 0) << "Invalid AES key size.";
|
||||
std::array<uint8_t, kAesBlockByteSize> encrypted_bytes;
|
||||
// Bytes_to_encrypt is less than 16 bytes and can be guaranteed to be a
|
||||
// single block, so we encrypt it using AES ECB mode (Approved by: b/73360609)
|
||||
AES_encrypt(bytes_to_encrypt.data(), encrypted_bytes.data(), &aes_key);
|
||||
return encrypted_bytes;
|
||||
}
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_FAST_PAIR_ENCRYPTION_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_ENCRYPTION_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/handshake/fast_pair_key_pair.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
/** Utilities used for generating Ecdh key agreement and
|
||||
* encrypting Fast Pair packets. */
|
||||
class FastPairEncryption {
|
||||
public:
|
||||
static absl::optional<KeyPair> GenerateKeysWithEcdhKeyAgreement(
|
||||
std::string_view decoded_public_anti_spoofing);
|
||||
|
||||
static std::array<uint8_t, kAesBlockByteSize> EncryptBytes(
|
||||
const std::array<uint8_t, kAesBlockByteSize>& aes_key_bytes,
|
||||
const std::array<uint8_t, kAesBlockByteSize>& bytes_to_encrypt);
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_ENCRYPTION_H_
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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 "fastpair/handshake/fast_pair_encryption.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
// All test data comes from
|
||||
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
|
||||
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> aes_key_bytes = {
|
||||
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6,
|
||||
0xCF, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D};
|
||||
|
||||
std::string DecodeKey(const std::string& encoded_key) {
|
||||
std::string key;
|
||||
absl::Base64Unescape(encoded_key, &key);
|
||||
return key;
|
||||
}
|
||||
|
||||
class FastPairEncryptionTest : public testing::Test {};
|
||||
|
||||
TEST(FastPairEncryptionTest, EncryptBytes_Success) {
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> input = {
|
||||
0xF3, 0x0F, 0x4E, 0x78, 0x6C, 0x59, 0xA7, 0xBB,
|
||||
0xF3, 0x87, 0x3B, 0x5A, 0x49, 0xBA, 0x97, 0xEA};
|
||||
|
||||
constexpr std::array<uint8_t, kAesBlockByteSize> expected = {
|
||||
0xAC, 0x9A, 0x16, 0xF0, 0x95, 0x3A, 0x3F, 0x22,
|
||||
0x3D, 0xD1, 0x0C, 0xF5, 0x36, 0xE0, 0x9E, 0x9C};
|
||||
|
||||
EXPECT_EQ(FastPairEncryption::EncryptBytes(aes_key_bytes, input), expected);
|
||||
}
|
||||
|
||||
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_EmptyKey) {
|
||||
EXPECT_FALSE(
|
||||
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement("").has_value());
|
||||
}
|
||||
|
||||
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_ShortKey) {
|
||||
EXPECT_FALSE(FastPairEncryption::GenerateKeysWithEcdhKeyAgreement("too_short")
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_InvalidKey) {
|
||||
EXPECT_FALSE(
|
||||
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
|
||||
DecodeKey("U2PWc3FHTxah/o0YT9n1VRvtm57SNIRSXOEBXm4fdtMo+06tNoFlt8D0/"
|
||||
"2BsN8auolz5ikwLRvQh+MiQ6oYveg=="))
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(FastPairEncryptionTest, GenerateKeysWithEcdhKeyAgreement_ValidKey) {
|
||||
EXPECT_TRUE(
|
||||
FastPairEncryption::GenerateKeysWithEcdhKeyAgreement(
|
||||
DecodeKey("U2PWc3FHTxah/o0YU9n1VRvtm57SNIRSXOEBXm4fdtMo+06tNoFlt8D0/"
|
||||
"2BsN8auolz5ikwLRvQh+MiQ6oYveg=="))
|
||||
.has_value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_FAST_PAIR_KEY_PAIR_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_KEY_PAIR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "fastpair/common/constant.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Key pair structure to represent public and private keys used for encryption/
|
||||
// decryption.
|
||||
struct KeyPair {
|
||||
KeyPair(
|
||||
const std::array<uint8_t, kSharedSecretKeyByteSize>& shared_secret_key,
|
||||
const std::array<uint8_t, kPublicKeyByteSize>& public_key)
|
||||
: shared_secret_key(std::move(shared_secret_key)),
|
||||
public_key(std::move(public_key)) {}
|
||||
|
||||
const std::array<uint8_t, kSharedSecretKeyByteSize> shared_secret_key;
|
||||
const std::array<uint8_t, kPublicKeyByteSize> public_key;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_KEY_PAIR_H_
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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 "fastpair/handshake/fast_pair_key_pair.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "protobuf-matchers/protocol-buffer-matchers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
// Test data comes from
|
||||
// https://developers.google.com/nearby/fast-pair/specifications/appendix/testcases#test_cases
|
||||
TEST(KeyPairTest, CreateKeyPair) {
|
||||
// Shared secret key bytes.
|
||||
constexpr std::array<uint8_t, kSharedSecretKeyByteSize>
|
||||
shared_secret_key_bytes = {0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F,
|
||||
0xF7, 0xB6, 0xCF, 0x5E, 0x3F, 0x45,
|
||||
0x61, 0xC3, 0x32, 0x1D};
|
||||
|
||||
// Public key bytes.
|
||||
constexpr std::array<uint8_t, kPublicKeyByteSize> public_key_bytes = {
|
||||
0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67,
|
||||
0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34,
|
||||
0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6,
|
||||
0x50, 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56,
|
||||
0xfb, 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27,
|
||||
0xc5, 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25};
|
||||
|
||||
KeyPair keyPair(shared_secret_key_bytes, public_key_bytes);
|
||||
|
||||
EXPECT_EQ(keyPair.shared_secret_key, shared_secret_key_bytes);
|
||||
EXPECT_EQ(keyPair.public_key, public_key_bytes);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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_FASTPAIR_HANDSHAKE_FAST_PAIR_MESSAGE_TYPE_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_MESSAGE_TYPE_H_
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Type values for Fast Pair messages.
|
||||
enum class FastPairMessageType {
|
||||
// Key-based Pairing Request.
|
||||
kKeyBasedPairingRequest,
|
||||
// Key-based Pairing Response.
|
||||
kKeyBasedPairingResponse,
|
||||
// Seeker's passkey.
|
||||
kSeekersPasskey,
|
||||
// Provider's passkey.
|
||||
kProvidersPasskey,
|
||||
// Unknown message type.
|
||||
kUnknown,
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_MESSAGE_TYPE_H_
|
||||
Reference in New Issue
Block a user