1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/browsing_topics/util.h"
7 #include "base/rand_util.h"
8 #include "base/ranges/algorithm.h"
9 #include "crypto/hmac.h"
10 #include "crypto/sha2.h"
11 #include "third_party/blink/public/common/features.h"
13 namespace browsing_topics {
17 // Note that updating the use case prefixes below will change the pre-existing
18 // per-user stickiness. Some of the derived data may already have been persisted
19 // elsewhere. Be sure you are aware of the implications before updating those
20 // strings. Note also that the version here is just about the hash method, and
21 // is distinctive from the broader configuration version of the Topics API.
22 const char kRandomOrTopTopicDecisionPrefix[] =
23 "TopicsV1_RandomOrTopTopicDecision|";
24 const char kRandomTopicIndexDecisionPrefix[] =
25 "TopicsV1_RandomTopicIndexDecision|";
26 const char kTopTopicIndexDecisionPrefix[] = "TopicsV1_TopTopicIndexDecision|";
27 const char kEpochSwitchTimeDecisionPrefix[] =
28 "TopicsV1_EpochSwitchTimeDecision|";
29 const char kContextDomainStoragePrefix[] = "TopicsV1_ContextDomainStorage|";
30 const char kMainFrameHostStoragePrefix[] = "TopicsV1_MainFrameHostStorage|";
32 uint64_t HmacHash(ReadOnlyHmacKey hmac_key,
33 const std::string& use_case_prefix,
34 const std::string& data) {
35 crypto::HMAC hmac(crypto::HMAC::SHA256);
36 CHECK(hmac.Init(hmac_key));
39 CHECK(hmac.Sign(use_case_prefix + data,
40 reinterpret_cast<unsigned char*>(&result), sizeof(result)));
45 bool g_hmac_key_overridden = false;
47 browsing_topics::HmacKey& GetHmacKeyOverrideForTesting() {
48 static browsing_topics::HmacKey key;
54 HmacKey GenerateRandomHmacKey() {
55 if (g_hmac_key_overridden)
56 return GetHmacKeyOverrideForTesting();
59 base::RandBytes(result.data(), result.size());
64 uint64_t HashTopDomainForRandomOrTopTopicDecision(
65 ReadOnlyHmacKey hmac_key,
66 base::Time epoch_calculation_time,
67 const std::string& top_domain) {
68 int64_t time_microseconds =
69 epoch_calculation_time.ToDeltaSinceWindowsEpoch().InMicroseconds();
71 std::string epoch_id(reinterpret_cast<const char*>(&time_microseconds),
72 sizeof(time_microseconds));
74 return HmacHash(hmac_key, kRandomOrTopTopicDecisionPrefix,
75 epoch_id + top_domain);
78 uint64_t HashTopDomainForRandomTopicIndexDecision(
79 ReadOnlyHmacKey hmac_key,
80 base::Time epoch_calculation_time,
81 const std::string& top_domain) {
82 int64_t time_microseconds =
83 epoch_calculation_time.ToDeltaSinceWindowsEpoch().InMicroseconds();
85 std::string epoch_id(reinterpret_cast<const char*>(&time_microseconds),
86 sizeof(time_microseconds));
88 return HmacHash(hmac_key, kRandomTopicIndexDecisionPrefix,
89 epoch_id + top_domain);
92 uint64_t HashTopDomainForTopTopicIndexDecision(
93 ReadOnlyHmacKey hmac_key,
94 base::Time epoch_calculation_time,
95 const std::string& top_domain) {
96 int64_t time_microseconds =
97 epoch_calculation_time.ToDeltaSinceWindowsEpoch().InMicroseconds();
99 std::string epoch_id(reinterpret_cast<const char*>(&time_microseconds),
100 sizeof(time_microseconds));
102 return HmacHash(hmac_key, kTopTopicIndexDecisionPrefix,
103 epoch_id + top_domain);
106 uint64_t HashTopDomainForEpochSwitchTimeDecision(
107 ReadOnlyHmacKey hmac_key,
108 const std::string& top_domain) {
109 return HmacHash(hmac_key, kEpochSwitchTimeDecisionPrefix, top_domain);
112 HashedDomain HashContextDomainForStorage(ReadOnlyHmacKey hmac_key,
113 const std::string& context_domain) {
115 HmacHash(hmac_key, kContextDomainStoragePrefix, context_domain));
118 HashedHost HashMainFrameHostForStorage(const std::string& main_frame_host) {
120 crypto::SHA256HashString(kMainFrameHostStoragePrefix + main_frame_host,
121 &result, sizeof(result));
122 return HashedHost(result);
125 void OverrideHmacKeyForTesting(ReadOnlyHmacKey hmac_key) {
126 g_hmac_key_overridden = true;
127 base::ranges::copy(hmac_key, GetHmacKeyOverrideForTesting().begin());
130 } // namespace browsing_topics