blob: 99dc79e819efaefe578af3f1041f01078a724649 [file] [log] [blame]
// 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.
#include "chromeos/services/secure_channel/background_eid_generator.h"
#include <cstring>
#include <memory>
#include "base/strings/string_util.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "chromeos/components/multidevice/beacon_seed.h"
#include "chromeos/components/multidevice/remote_device_ref.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h"
#include "chromeos/services/secure_channel/raw_eid_generator.h"
#include "chromeos/services/secure_channel/raw_eid_generator_impl.h"
namespace chromeos {
namespace secure_channel {
namespace {
// The duration of a EID period in milliseconds.
const int64_t kEidPeriodMs = 15 * 60 * 1000; // 15 minutes
// The number of periods to look forward and backwards when calculating the
// neartest EIDs.
const int kEidLookAhead = 2;
// Returns the BeaconSeed valid for |timestamp_ms|, or nullptr if none can be
// found.
const cryptauth::BeaconSeed* GetBeaconSeedForTimestamp(
int64_t timestamp_ms,
const std::vector<cryptauth::BeaconSeed>& beacon_seeds) {
for (const cryptauth::BeaconSeed& seed : beacon_seeds) {
if (timestamp_ms >= seed.start_time_millis() &&
timestamp_ms <= seed.end_time_millis()) {
return &seed;
}
}
return nullptr;
}
} // namespace
BackgroundEidGenerator::BackgroundEidGenerator()
: BackgroundEidGenerator(std::make_unique<RawEidGeneratorImpl>(),
base::DefaultClock::GetInstance()) {}
BackgroundEidGenerator::~BackgroundEidGenerator() {}
BackgroundEidGenerator::BackgroundEidGenerator(
std::unique_ptr<RawEidGenerator> raw_eid_generator,
base::Clock* clock)
: raw_eid_generator_(std::move(raw_eid_generator)), clock_(clock) {}
std::vector<DataWithTimestamp> BackgroundEidGenerator::GenerateNearestEids(
const std::vector<cryptauth::BeaconSeed>& beacon_seeds) const {
int64_t now_timestamp_ms = clock_->Now().ToJavaTime();
std::vector<DataWithTimestamp> eids;
for (int i = -kEidLookAhead; i <= kEidLookAhead; ++i) {
int64_t timestamp_ms = now_timestamp_ms + i * kEidPeriodMs;
std::unique_ptr<DataWithTimestamp> eid =
GenerateEid(timestamp_ms, beacon_seeds);
if (eid)
eids.push_back(*eid);
}
return eids;
}
std::unique_ptr<DataWithTimestamp> BackgroundEidGenerator::GenerateEid(
int64_t timestamp_ms,
const std::vector<cryptauth::BeaconSeed>& beacon_seeds) const {
const cryptauth::BeaconSeed* beacon_seed =
GetBeaconSeedForTimestamp(timestamp_ms, beacon_seeds);
if (!beacon_seed) {
PA_LOG(WARNING) << " " << timestamp_ms << ": outside of BeaconSeed range.";
return nullptr;
}
int64_t seed_start_time_ms = beacon_seed->start_time_millis();
int64_t offset_time_ms = timestamp_ms - seed_start_time_ms;
int64_t start_of_period_ms =
seed_start_time_ms + (offset_time_ms / kEidPeriodMs) * kEidPeriodMs;
std::string eid = raw_eid_generator_->GenerateEid(
beacon_seed->data(), start_of_period_ms, nullptr);
return std::make_unique<DataWithTimestamp>(eid, start_of_period_ms,
start_of_period_ms + kEidPeriodMs);
}
std::string BackgroundEidGenerator::IdentifyRemoteDeviceByAdvertisement(
const std::string& advertisement_service_data,
const chromeos::multidevice::RemoteDeviceRefList& remote_devices) const {
// Resize the service data to analyze only the first |kNumBytesInEidValue|
// bytes. If there are any bytes after those first |kNumBytesInEidValue|
// bytes, they are flags, so they are not needed to identify the device which
// sent a message.
std::string service_data_without_flags = advertisement_service_data;
service_data_without_flags.resize(RawEidGenerator::kNumBytesInEidValue);
const auto remote_device_it = std::find_if(
remote_devices.begin(), remote_devices.end(),
[this, &service_data_without_flags](const auto& remote_device) {
std::vector<DataWithTimestamp> eids =
GenerateNearestEids(chromeos::multidevice::ToCryptAuthSeedList(
remote_device.beacon_seeds()));
const auto eid_it = std::find_if(
eids.begin(), eids.end(), [&service_data_without_flags](auto eid) {
return eid.data == service_data_without_flags;
});
return eid_it != eids.end();
});
// Return empty string if no matching device is found.
return remote_device_it != remote_devices.end()
? remote_device_it->GetDeviceId()
: std::string();
}
} // namespace secure_channel
} // namespace chromeos