OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/computed_hashes.h" | 5 #include "extensions/browser/computed_hashes.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 12 #include "base/stl_util.h" |
| 13 #include "base/values.h" |
| 14 #include "crypto/secure_hash.h" |
| 15 #include "crypto/sha2.h" |
12 | 16 |
13 namespace { | 17 namespace { |
| 18 const char kBlockHashesKey[] = "block_hashes"; |
| 19 const char kBlockSizeKey[] = "block_size"; |
| 20 const char kFileHashesKey[] = "file_hashes"; |
14 const char kPathKey[] = "path"; | 21 const char kPathKey[] = "path"; |
15 const char kBlockSizeKey[] = "block_size"; | 22 const char kVersionKey[] = "version"; |
16 const char kBlockHashesKey[] = "block_hashes"; | 23 const int kVersion = 2; |
17 } | 24 } // namespace |
18 | 25 |
19 namespace extensions { | 26 namespace extensions { |
20 | 27 |
21 ComputedHashes::Reader::Reader() { | 28 ComputedHashes::Reader::Reader() { |
22 } | 29 } |
| 30 |
23 ComputedHashes::Reader::~Reader() { | 31 ComputedHashes::Reader::~Reader() { |
24 } | 32 } |
25 | 33 |
26 bool ComputedHashes::Reader::InitFromFile(const base::FilePath& path) { | 34 bool ComputedHashes::Reader::InitFromFile(const base::FilePath& path) { |
27 std::string contents; | 35 std::string contents; |
28 if (!base::ReadFileToString(path, &contents)) | 36 if (!base::ReadFileToString(path, &contents)) |
29 return false; | 37 return false; |
30 | 38 |
| 39 base::DictionaryValue* top_dictionary = NULL; |
| 40 scoped_ptr<base::Value> value(base::JSONReader::Read(contents)); |
| 41 if (!value.get() || !value->GetAsDictionary(&top_dictionary)) |
| 42 return false; |
| 43 |
| 44 // For now we don't support forwards or backwards compatability in the |
| 45 // format, so we return false on version mismatch. |
| 46 int version = 0; |
| 47 if (!top_dictionary->GetInteger(kVersionKey, &version) || version != kVersion) |
| 48 return false; |
| 49 |
31 base::ListValue* all_hashes = NULL; | 50 base::ListValue* all_hashes = NULL; |
32 scoped_ptr<base::Value> value(base::JSONReader::Read(contents)); | 51 if (!top_dictionary->GetList(kFileHashesKey, &all_hashes)) |
33 if (!value.get() || !value->GetAsList(&all_hashes)) | |
34 return false; | 52 return false; |
35 | 53 |
36 for (size_t i = 0; i < all_hashes->GetSize(); i++) { | 54 for (size_t i = 0; i < all_hashes->GetSize(); i++) { |
37 base::DictionaryValue* dictionary = NULL; | 55 base::DictionaryValue* dictionary = NULL; |
38 if (!all_hashes->GetDictionary(i, &dictionary)) | 56 if (!all_hashes->GetDictionary(i, &dictionary)) |
39 return false; | 57 return false; |
40 | 58 |
41 std::string relative_path_utf8; | 59 std::string relative_path_utf8; |
42 if (!dictionary->GetString(kPathKey, &relative_path_utf8)) | 60 if (!dictionary->GetString(kPathKey, &relative_path_utf8)) |
43 return false; | 61 return false; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 base::FilePath path = relative_path.NormalizePathSeparatorsTo('/'); | 102 base::FilePath path = relative_path.NormalizePathSeparatorsTo('/'); |
85 std::map<base::FilePath, HashInfo>::iterator i = data_.find(path); | 103 std::map<base::FilePath, HashInfo>::iterator i = data_.find(path); |
86 if (i == data_.end()) | 104 if (i == data_.end()) |
87 return false; | 105 return false; |
88 HashInfo& info = i->second; | 106 HashInfo& info = i->second; |
89 *block_size = info.first; | 107 *block_size = info.first; |
90 *hashes = info.second; | 108 *hashes = info.second; |
91 return true; | 109 return true; |
92 } | 110 } |
93 | 111 |
94 ComputedHashes::Writer::Writer() { | 112 ComputedHashes::Writer::Writer() : file_list_(new base::ListValue) { |
95 } | 113 } |
| 114 |
96 ComputedHashes::Writer::~Writer() { | 115 ComputedHashes::Writer::~Writer() { |
97 } | 116 } |
98 | 117 |
99 void ComputedHashes::Writer::AddHashes(const base::FilePath& relative_path, | 118 void ComputedHashes::Writer::AddHashes(const base::FilePath& relative_path, |
100 int block_size, | 119 int block_size, |
101 const std::vector<std::string>& hashes) { | 120 const std::vector<std::string>& hashes) { |
102 base::DictionaryValue* dict = new base::DictionaryValue(); | 121 base::DictionaryValue* dict = new base::DictionaryValue(); |
103 base::ListValue* block_hashes = new base::ListValue(); | 122 base::ListValue* block_hashes = new base::ListValue(); |
104 file_list_.Append(dict); | 123 file_list_->Append(dict); |
105 dict->SetString(kPathKey, | 124 dict->SetString(kPathKey, |
106 relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe()); | 125 relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe()); |
107 dict->SetInteger(kBlockSizeKey, block_size); | 126 dict->SetInteger(kBlockSizeKey, block_size); |
108 dict->Set(kBlockHashesKey, block_hashes); | 127 dict->Set(kBlockHashesKey, block_hashes); |
109 | 128 |
110 for (std::vector<std::string>::const_iterator i = hashes.begin(); | 129 for (std::vector<std::string>::const_iterator i = hashes.begin(); |
111 i != hashes.end(); | 130 i != hashes.end(); |
112 ++i) { | 131 ++i) { |
113 std::string encoded; | 132 std::string encoded; |
114 base::Base64Encode(*i, &encoded); | 133 base::Base64Encode(*i, &encoded); |
115 block_hashes->AppendString(encoded); | 134 block_hashes->AppendString(encoded); |
116 } | 135 } |
117 } | 136 } |
118 | 137 |
119 bool ComputedHashes::Writer::WriteToFile(const base::FilePath& path) { | 138 bool ComputedHashes::Writer::WriteToFile(const base::FilePath& path) { |
120 std::string json; | 139 std::string json; |
121 if (!base::JSONWriter::Write(&file_list_, &json)) | 140 base::DictionaryValue top_dictionary; |
| 141 top_dictionary.SetInteger(kVersionKey, kVersion); |
| 142 top_dictionary.Set(kFileHashesKey, file_list_.release()); |
| 143 |
| 144 if (!base::JSONWriter::Write(&top_dictionary, &json)) |
122 return false; | 145 return false; |
123 int written = base::WriteFile(path, json.data(), json.size()); | 146 int written = base::WriteFile(path, json.data(), json.size()); |
124 if (static_cast<unsigned>(written) != json.size()) { | 147 if (static_cast<unsigned>(written) != json.size()) { |
125 LOG(ERROR) << "Error writing " << path.MaybeAsASCII() | 148 LOG(ERROR) << "Error writing " << path.AsUTF8Unsafe() |
126 << " ; write result:" << written << " expected:" << json.size(); | 149 << " ; write result:" << written << " expected:" << json.size(); |
127 return false; | 150 return false; |
128 } | 151 } |
129 return true; | 152 return true; |
130 } | 153 } |
131 | 154 |
| 155 void ComputedHashes::ComputeHashesForContent(const std::string& contents, |
| 156 size_t block_size, |
| 157 std::vector<std::string>* hashes) { |
| 158 size_t offset = 0; |
| 159 // Even when the contents is empty, we want to output at least one hash |
| 160 // block (the hash of the empty string). |
| 161 do { |
| 162 const char* block_start = contents.data() + offset; |
| 163 DCHECK(offset <= contents.size()); |
| 164 size_t bytes_to_read = std::min(contents.size() - offset, block_size); |
| 165 scoped_ptr<crypto::SecureHash> hash( |
| 166 crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
| 167 hash->Update(block_start, bytes_to_read); |
| 168 |
| 169 hashes->push_back(std::string()); |
| 170 std::string* buffer = &(hashes->back()); |
| 171 buffer->resize(crypto::kSHA256Length); |
| 172 hash->Finish(string_as_array(buffer), buffer->size()); |
| 173 |
| 174 // If |contents| is empty, then we want to just exit here. |
| 175 if (bytes_to_read == 0) |
| 176 break; |
| 177 |
| 178 offset += bytes_to_read; |
| 179 } while (offset < contents.size()); |
| 180 } |
| 181 |
132 } // namespace extensions | 182 } // namespace extensions |
OLD | NEW |