OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/prefs/pref_hash_calculator.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/json/json_string_value_serializer.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/strings/string_number_conversions.h" | |
13 #include "base/strings/string_util.h" | |
14 #include "base/values.h" | |
15 #include "crypto/hmac.h" | |
16 | |
17 #if defined (OS_WIN) && defined(ENABLE_RLZ) | |
18 #include "rlz/lib/machine_id.h" | |
19 #endif | |
20 namespace { | |
gab
2013/11/27 23:43:27
nit: +empty line above
| |
21 | |
22 // Renders |value| as a string. |value| may be NULL, in which case the result | |
23 // is an empty string. | |
24 std::string ValueAsString(const base::Value* value) { | |
25 // Dictionary values may contain empty lists and sub-dictionaries. Make a | |
26 // deep copy with those removed to make the hash more stable. | |
27 const base::DictionaryValue* dict_value; | |
28 scoped_ptr<DictionaryValue> canonical_dict_value; | |
29 if (value && value->GetAsDictionary(&dict_value)) { | |
30 canonical_dict_value.reset(dict_value->DeepCopyWithoutEmptyChildren()); | |
31 value = canonical_dict_value.get(); | |
32 } | |
33 | |
34 std::string value_as_string; | |
35 if (value) { | |
36 JSONStringValueSerializer serializer(&value_as_string); | |
37 serializer.Serialize(*value); | |
38 } | |
39 | |
40 return value_as_string; | |
41 } | |
42 | |
43 // Common helper for all hash algorithms. | |
44 std::string CalculateFromValueAndComponents( | |
45 const std::string& seed, | |
46 const base::Value* value, | |
47 const std::vector<std::string>& extra_components) { | |
48 static const size_t kSHA256DigestSize = 32; | |
49 | |
50 std::string message = JoinString(extra_components, "") + ValueAsString(value); | |
51 | |
52 crypto::HMAC hmac(crypto::HMAC::SHA256); | |
53 unsigned char digest[kSHA256DigestSize]; | |
54 if (!hmac.Init(seed) || !hmac.Sign(message, digest, arraysize(digest))) { | |
55 NOTREACHED(); | |
56 return std::string(); | |
57 } | |
58 | |
59 return base::HexEncode(digest, arraysize(digest)); | |
60 } | |
61 | |
62 | |
63 // Common signature for current and legacy hash algorithms. | |
64 typedef std::string (CalculateFunctor)(const std::string& seed, | |
65 const std::string& path, | |
66 const base::Value* value); | |
67 | |
68 #if defined(OS_WIN) && defined(ENABLE_RLZ) | |
69 // Current algorithm on Windows. | |
70 std::string CalculateWithDeviceId(const std::string& seed, | |
71 const std::string& path, | |
72 const base::Value* value) { | |
73 std::vector<std::string> components; | |
74 | |
75 // This is used by | |
76 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc | |
77 // but that API is private and other platforms are not available | |
78 // synchronously. | |
79 // As part of improving pref metrics on other platforms we may want to find | |
80 // ways to defer preference loading until the device ID can be used. | |
81 components.resize(2); | |
82 rlz_lib::GetMachineId(&components[0]); | |
83 components[1] = path; | |
84 return CalculateFromValueAndComponents(seed, value, components); | |
85 } | |
86 #else | |
87 // Current algorithm when device ID is not available synchronously. | |
88 std::string CalculateWithPath(const std::string& seed, | |
89 const std::string& path, | |
90 const base::Value* value) { | |
91 std::vector<std::string> components; | |
92 components.insert(components.begin(), path); | |
gab
2013/11/27 23:43:27
components.push_back(path); would be simpler here.
| |
93 return CalculateFromValueAndComponents(seed, value, components); | |
94 } | |
95 #endif | |
96 | |
97 // Legacy algorithm. | |
98 std::string CalculateWithValueOnly(const std::string& seed, | |
99 const std::string& path, | |
100 const base::Value* value) { | |
101 return CalculateFromValueAndComponents(seed, | |
102 value, | |
103 std::vector<std::string>()); | |
104 } | |
105 | |
106 // Put the "modern" calculator followed by all deprecated calculators from which | |
107 // migration is supported. | |
108 static CalculateFunctor* const kCalculators[] = { | |
109 #if defined(OS_WIN) && defined(ENABLE_RLZ) | |
110 CalculateWithDeviceId, | |
111 #else | |
112 CalculateWithPath, | |
113 #endif | |
114 CalculateWithValueOnly | |
115 }; | |
116 | |
117 } // namespace | |
118 | |
119 PrefHashCalculator::PrefHashCalculator(const std::string& seed) : seed_(seed) {} | |
120 | |
121 PrefHashCalculator::ValidationResult PrefHashCalculator::Validate( | |
122 const std::string& path, | |
123 const base::Value* value, | |
124 const std::string& hash) { | |
125 // Attempt validation with each of the supported algorithms. | |
126 for (size_t i = 0; i < arraysize(kCalculators); ++i) { | |
127 if (hash == kCalculators[i](seed_, path, value)) | |
128 return i == 0 ? VALID : VALID_LEGACY; | |
gab
2013/11/27 23:43:27
I love the CalculateFunctor approach, but it seems
erikwright (departed)
2013/11/28 17:48:07
Actually already refactored this in the patchset t
| |
129 } | |
130 return INVALID; | |
131 } | |
132 | |
133 std::string PrefHashCalculator::Calculate(const std::string& path, | |
134 const base::Value* value) { | |
135 // Use the current (first listed) algorithm to calculate the hash. | |
136 return kCalculators[0](seed_, path, value); | |
137 } | |
OLD | NEW |