Chromium Code Reviews| 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 |