// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_CRYPTAUTH_BLE_EID_GENERATOR_H_ #define COMPONENTS_CRYPTAUTH_BLE_EID_GENERATOR_H_ #include #include #include #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/singleton.h" #include "base/time/clock.h" namespace cryptauth { class BeaconSeed; struct RemoteDevice; // Generates ephemeral ID (EID) values for BLE communication in ProximityAuth. // // A peripheral-role device advertises a 4-byte advertisement with two parts: a // 2-byte EID which is specific to the central-role device with which it intends // to communicate, and a 2-byte EID which is specific to the peripheral-role // device. // // This class uses EID seed values synced from the back-end to generate these // EIDs. // // See go/proximity-auth-ble-advertising. class EidGenerator { public: // Stores EID-related data and timestamps at which time this data becomes // active or inactive. struct DataWithTimestamp { DataWithTimestamp(const std::string& data, const int64_t start_timestamp_ms, const int64_t end_timestamp_ms); DataWithTimestamp(const DataWithTimestamp& other); bool ContainsTime(const int64_t timestamp_ms) const; std::string DataInHex() const; const std::string data; const int64_t start_timestamp_ms; const int64_t end_timestamp_ms; }; // Data for both a current and adjacent EID. The current EID *must* be // supplied, but adjacent data may be null. Each EID consists of a 2-byte EID // value paired with the timestamp at which time this value becomes active or // inactive. struct EidData { enum AdjacentDataType { NONE, PAST, FUTURE }; EidData(const DataWithTimestamp current_data, std::unique_ptr adjacent_data); ~EidData(); AdjacentDataType GetAdjacentDataType() const; std::string DataInHex() const; const DataWithTimestamp current_data; const std::unique_ptr adjacent_data; }; // The flag used to denote that a Bluetooth 4.0 device has sent an // advertisement. This flag indicates to the recipient that the sender cannot // act as both a central- and peripheral-role device simultaneously, so the // recipient should advertise back instead of initializing a connection. static const int8_t kBluetooth4Flag; static EidGenerator* GetInstance(); virtual ~EidGenerator(); // Generates EID data for the given EID seeds to be used as a background scan // filter. In the normal case, two DataWithTimestamp values are returned, one // for each EID seed rotation period. If data has not been synced from the // backend recently and EID seeds are unavailable, nullptr is returned. virtual std::unique_ptr GenerateBackgroundScanFilter( const std::vector& scanning_device_beacon_seeds) const; // Generates advertisement data for the given EID seeds. If data has not been // synced from the back-end recently and EID seeds are unavailable, nullptr is // returned. virtual std::unique_ptr GenerateAdvertisement( const std::string& advertising_device_public_key, const std::vector& scanning_device_beacon_seeds) const; // Generates all possible advertisements that could be created by a device // given that device's public key and the beacon seeds of the device which is // intended to scan for the advertisement. virtual std::vector GeneratePossibleAdvertisements( const std::string& advertising_device_public_key, const std::vector& scanning_device_beacon_seeds) const; // Given a list of RemoteDevices, identifies the device which could have // produced the supplied advertisement service data. virtual RemoteDevice const* IdentifyRemoteDeviceByAdvertisement( const std::string& advertisement_service_data, const std::vector& device_list, const std::vector& scanning_device_beacon_seeds) const; protected: EidGenerator(); private: friend struct base::DefaultSingletonTraits; struct EidPeriodTimestamps { int64_t current_period_start_timestamp_ms; int64_t current_period_end_timestamp_ms; int64_t adjacent_period_start_timestamp_ms; int64_t adjacent_period_end_timestamp_ms; }; class EidComputationHelper { public: virtual std::string GenerateEidDataForDevice( const std::string& eid_seed, const int64_t start_of_period_timestamp_ms, const std::string* extra_entropy) = 0; }; class EidComputationHelperImpl : public EidComputationHelper { public: std::string GenerateEidDataForDevice( const std::string& eid_seed, const int64_t start_of_period_timestamp_ms, const std::string* extra_entropy) override; }; static const int64_t kNumMsInEidPeriod; static const int64_t kNumMsInBeginningOfEidPeriod; static const int32_t kNumBytesInEidValue; EidGenerator(std::unique_ptr computation_helper, std::unique_ptr clock); std::unique_ptr GenerateAdvertisement( const std::string& advertising_device_public_key, const std::vector& scanning_device_beacon_seeds, const int64_t start_of_period_timestamp_ms, const int64_t end_of_period_timestamp_ms) const; std::unique_ptr GenerateEidDataWithTimestamp( const std::vector& scanning_device_beacon_seeds, const int64_t start_of_period_timestamp_ms, const int64_t end_of_period_timestamp_ms) const; std::unique_ptr GenerateEidDataWithTimestamp( const std::vector& scanning_device_beacon_seeds, const int64_t start_of_period_timestamp_ms, const int64_t end_of_period_timestamp_ms, const std::string* extra_entropy) const; std::unique_ptr GetEidSeedForPeriod( const std::vector& scanning_device_beacon_seeds, const int64_t start_of_period_timestamp_ms) const; std::unique_ptr GetEidPeriodTimestamps( const std::vector& scanning_device_beacon_seeds) const; std::unique_ptr GetEidPeriodTimestamps( const std::vector& scanning_device_beacon_seeds, const bool allow_non_current_periods) const; std::unique_ptr GetBeaconSeedForCurrentPeriod( const std::vector& scanning_device_beacon_seeds, const int64_t current_time_ms) const; std::unique_ptr GetClosestPeriod( const std::vector& scanning_device_beacon_seeds, const int64_t current_time_ms) const; static bool IsCurrentTimeAtStartOfEidPeriod( const int64_t start_of_period_timestamp_ms, const int64_t end_of_period_timestamp_ms, const int64_t current_timestamp_ms); std::unique_ptr clock_; std::unique_ptr eid_computation_helper_; DISALLOW_COPY_AND_ASSIGN(EidGenerator); friend class CryptAuthEidGeneratorTest; FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGenerateEidDataForDevice_UsingRealEidComputationHelper); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_CurrentAndPastAdjacentPeriods); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, testGeneratePossibleAdvertisements_CurrentAndFutureAdjacentPeriods); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_OnlyCurrentPeriod); FRIEND_TEST_ALL_PREFIXES(CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_OnlyFuturePeriod); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_NoAdvertisements_SeedsTooFarInFuture); FRIEND_TEST_ALL_PREFIXES(CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_OnlyPastPeriod); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_NoAdvertisements_SeedsTooFarInPast); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestGeneratePossibleAdvertisements_NoAdvertisements_EmptySeeds); FRIEND_TEST_ALL_PREFIXES(CryptAuthEidGeneratorTest, TestEidComputationHelperImpl_ProducesTwoByteValue); FRIEND_TEST_ALL_PREFIXES(CryptAuthEidGeneratorTest, TestEidComputationHelperImpl_Deterministic); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestEidComputationHelperImpl_ChangingSeedChangesOutput); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestEidComputationHelperImpl_ChangingTimestampChangesOutput); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestEidComputationHelperImpl_ChangingExtraEntropyChangesOutput); FRIEND_TEST_ALL_PREFIXES( CryptAuthEidGeneratorTest, TestEidComputationHelper_ChangingTimestampWithLongExtraEntropy); FRIEND_TEST_ALL_PREFIXES(CryptAuthEidGeneratorTest, TestEidComputationHelper_EnsureTestVectorsPass); }; } #endif // COMPONENTS_CRYPTAUTH_BLE_EID_GENERATOR_H_