Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: chrome/browser/sync/util/cryptographer.cc

Issue 8468023: Move encryption related files from util folder to encryption folder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: For review. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "base/base64.h"
6 #include "chrome/browser/sync/util/cryptographer.h"
7 #include "chrome/browser/password_manager/encryptor.h"
8
9 namespace browser_sync {
10
11 const char kNigoriTag[] = "google_chrome_nigori";
12
13 // We name a particular Nigori instance (ie. a triplet consisting of a hostname,
14 // a username, and a password) by calling Permute on this string. Since the
15 // output of Permute is always the same for a given triplet, clients will always
16 // assign the same name to a particular triplet.
17 const char kNigoriKeyName[] = "nigori-key";
18
19 Cryptographer::Observer::~Observer() {}
20
21 Cryptographer::Cryptographer()
22 : default_nigori_(NULL),
23 encrypt_everything_(false) {
24 syncable::ModelTypeSet sensitive_types = SensitiveTypes();
25 encrypted_types_.insert(sensitive_types.begin(), sensitive_types.end());
26 }
27
28 Cryptographer::~Cryptographer() {}
29
30 void Cryptographer::AddObserver(Observer* observer) {
31 observers_.AddObserver(observer);
32 }
33
34 void Cryptographer::RemoveObserver(Observer* observer) {
35 observers_.RemoveObserver(observer);
36 }
37
38 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) {
39 if (is_initialized()) {
40 NOTREACHED();
41 return;
42 }
43
44 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token));
45 if (nigori.get())
46 AddKeyImpl(nigori.release());
47 }
48
49 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const {
50 return nigoris_.end() != nigoris_.find(data.key_name());
51 }
52
53 bool Cryptographer::CanDecryptUsingDefaultKey(
54 const sync_pb::EncryptedData& data) const {
55 return default_nigori_ && (data.key_name() == default_nigori_->first);
56 }
57
58 bool Cryptographer::Encrypt(const ::google::protobuf::MessageLite& message,
59 sync_pb::EncryptedData* encrypted) const {
60 if (!encrypted || !default_nigori_) {
61 LOG(ERROR) << "Cryptographer not ready, failed to encrypt.";
62 return false;
63 }
64
65 std::string serialized;
66 if (!message.SerializeToString(&serialized)) {
67 LOG(ERROR) << "Message is invalid/missing a required field.";
68 return false;
69 }
70
71 encrypted->set_key_name(default_nigori_->first);
72 if (!default_nigori_->second->Encrypt(serialized,
73 encrypted->mutable_blob())) {
74 LOG(ERROR) << "Failed to encrypt data.";
75 return false;
76 }
77 return true;
78 }
79
80 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted,
81 ::google::protobuf::MessageLite* message) const {
82 DCHECK(message);
83 std::string plaintext = DecryptToString(encrypted);
84 return message->ParseFromString(plaintext);
85 }
86
87 std::string Cryptographer::DecryptToString(
88 const sync_pb::EncryptedData& encrypted) const {
89 NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name());
90 if (nigoris_.end() == it) {
91 NOTREACHED() << "Cannot decrypt message";
92 return std::string(""); // Caller should have called CanDecrypt(encrypt).
93 }
94
95 std::string plaintext;
96 if (!it->second->Decrypt(encrypted.blob(), &plaintext)) {
97 return std::string("");
98 }
99
100 return plaintext;
101 }
102
103 bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
104 DCHECK(encrypted);
105 DCHECK(!nigoris_.empty());
106
107 // Create a bag of all the Nigori parameters we know about.
108 sync_pb::NigoriKeyBag bag;
109 for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end();
110 ++it) {
111 const Nigori& nigori = *it->second;
112 sync_pb::NigoriKey* key = bag.add_key();
113 key->set_name(it->first);
114 nigori.ExportKeys(key->mutable_user_key(),
115 key->mutable_encryption_key(),
116 key->mutable_mac_key());
117 }
118
119 // Encrypt the bag with the default Nigori.
120 return Encrypt(bag, encrypted);
121 }
122
123 bool Cryptographer::AddKey(const KeyParams& params) {
124 DCHECK(NULL == pending_keys_.get());
125
126 // Create the new Nigori and make it the default encryptor.
127 scoped_ptr<Nigori> nigori(new Nigori);
128 if (!nigori->InitByDerivation(params.hostname,
129 params.username,
130 params.password)) {
131 NOTREACHED(); // Invalid username or password.
132 return false;
133 }
134 return AddKeyImpl(nigori.release());
135 }
136
137 bool Cryptographer::AddKeyImpl(Nigori* initialized_nigori) {
138 scoped_ptr<Nigori> nigori(initialized_nigori);
139 std::string name;
140 if (!nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) {
141 NOTREACHED();
142 return false;
143 }
144 nigoris_[name] = make_linked_ptr(nigori.release());
145 default_nigori_ = &*nigoris_.find(name);
146 return true;
147 }
148
149 bool Cryptographer::SetKeys(const sync_pb::EncryptedData& encrypted) {
150 DCHECK(CanDecrypt(encrypted));
151
152 sync_pb::NigoriKeyBag bag;
153 if (!Decrypt(encrypted, &bag)) {
154 return false;
155 }
156 InstallKeys(encrypted.key_name(), bag);
157 return true;
158 }
159
160 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) {
161 DCHECK(!CanDecrypt(encrypted));
162 pending_keys_.reset(new sync_pb::EncryptedData(encrypted));
163 }
164
165 bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
166 Nigori nigori;
167 if (!nigori.InitByDerivation(params.hostname,
168 params.username,
169 params.password)) {
170 NOTREACHED();
171 return false;
172 }
173
174 std::string plaintext;
175 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext))
176 return false;
177
178 sync_pb::NigoriKeyBag bag;
179 if (!bag.ParseFromString(plaintext)) {
180 NOTREACHED();
181 return false;
182 }
183 InstallKeys(pending_keys_->key_name(), bag);
184 pending_keys_.reset();
185 return true;
186 }
187
188 bool Cryptographer::GetBootstrapToken(std::string* token) const {
189 DCHECK(token);
190 if (!is_initialized())
191 return false;
192
193 return PackBootstrapToken(default_nigori_->second.get(), token);
194 }
195
196 bool Cryptographer::PackBootstrapToken(const Nigori* nigori,
197 std::string* pack_into) const {
198 DCHECK(pack_into);
199 DCHECK(nigori);
200
201 sync_pb::NigoriKey key;
202 if (!nigori->ExportKeys(key.mutable_user_key(),
203 key.mutable_encryption_key(),
204 key.mutable_mac_key())) {
205 NOTREACHED();
206 return false;
207 }
208
209 std::string unencrypted_token;
210 if (!key.SerializeToString(&unencrypted_token)) {
211 NOTREACHED();
212 return false;
213 }
214
215 std::string encrypted_token;
216 if (!Encryptor::EncryptString(unencrypted_token, &encrypted_token)) {
217 NOTREACHED();
218 return false;
219 }
220
221 if (!base::Base64Encode(encrypted_token, pack_into)) {
222 NOTREACHED();
223 return false;
224 }
225 return true;
226 }
227
228 Nigori* Cryptographer::UnpackBootstrapToken(const std::string& token) const {
229 if (token.empty())
230 return NULL;
231
232 std::string encrypted_data;
233 if (!base::Base64Decode(token, &encrypted_data)) {
234 DLOG(WARNING) << "Could not decode token.";
235 return NULL;
236 }
237
238 std::string unencrypted_token;
239 if (!Encryptor::DecryptString(encrypted_data, &unencrypted_token)) {
240 DLOG(WARNING) << "Decryption of bootstrap token failed.";
241 return NULL;
242 }
243
244 sync_pb::NigoriKey key;
245 if (!key.ParseFromString(unencrypted_token)) {
246 DLOG(WARNING) << "Parsing of bootstrap token failed.";
247 return NULL;
248 }
249
250 scoped_ptr<Nigori> nigori(new Nigori);
251 if (!nigori->InitByImport(key.user_key(), key.encryption_key(),
252 key.mac_key())) {
253 NOTREACHED();
254 return NULL;
255 }
256
257 return nigori.release();
258 }
259
260 Cryptographer::UpdateResult Cryptographer::Update(
261 const sync_pb::NigoriSpecifics& nigori) {
262 UpdateEncryptedTypesFromNigori(nigori);
263 if (!nigori.encrypted().blob().empty()) {
264 if (CanDecrypt(nigori.encrypted())) {
265 SetKeys(nigori.encrypted());
266 return Cryptographer::SUCCESS;
267 } else {
268 SetPendingKeys(nigori.encrypted());
269 return Cryptographer::NEEDS_PASSPHRASE;
270 }
271 }
272 return Cryptographer::SUCCESS;
273 }
274
275 // Static
276 syncable::ModelTypeSet Cryptographer::SensitiveTypes() {
277 syncable::ModelTypeSet types;
278 // Both of these have their own encryption schemes, but we include them
279 // anyways.
280 types.insert(syncable::PASSWORDS);
281 types.insert(syncable::NIGORI);
282 return types;
283 }
284
285 void Cryptographer::UpdateEncryptedTypesFromNigori(
286 const sync_pb::NigoriSpecifics& nigori) {
287 if (nigori.encrypt_everything()) {
288 set_encrypt_everything();
289 return;
290 }
291
292 syncable::ModelTypeSet encrypted_types(SensitiveTypes());
293 if (nigori.encrypt_bookmarks())
294 encrypted_types.insert(syncable::BOOKMARKS);
295 if (nigori.encrypt_preferences())
296 encrypted_types.insert(syncable::PREFERENCES);
297 if (nigori.encrypt_autofill_profile())
298 encrypted_types.insert(syncable::AUTOFILL_PROFILE);
299 if (nigori.encrypt_autofill())
300 encrypted_types.insert(syncable::AUTOFILL);
301 if (nigori.encrypt_themes())
302 encrypted_types.insert(syncable::THEMES);
303 if (nigori.encrypt_typed_urls())
304 encrypted_types.insert(syncable::TYPED_URLS);
305 if (nigori.encrypt_extension_settings())
306 encrypted_types.insert(syncable::EXTENSION_SETTINGS);
307 if (nigori.encrypt_extensions())
308 encrypted_types.insert(syncable::EXTENSIONS);
309 if (nigori.encrypt_search_engines())
310 encrypted_types.insert(syncable::SEARCH_ENGINES);
311 if (nigori.encrypt_sessions())
312 encrypted_types.insert(syncable::SESSIONS);
313 if (nigori.encrypt_app_settings())
314 encrypted_types.insert(syncable::APP_SETTINGS);
315 if (nigori.encrypt_apps())
316 encrypted_types.insert(syncable::APPS);
317 if (nigori.encrypt_app_notifications())
318 encrypted_types.insert(syncable::APP_NOTIFICATIONS);
319
320 // Note: the initial version with encryption did not support the
321 // encrypt_everything field. If anything more than the sensitive types were
322 // encrypted, it meant we were encrypting everything.
323 if (!nigori.has_encrypt_everything() &&
324 encrypted_types.size() > SensitiveTypes().size()) {
325 set_encrypt_everything();
326 return;
327 }
328
329 SetEncryptedTypes(encrypted_types);
330 }
331
332 void Cryptographer::UpdateNigoriFromEncryptedTypes(
333 sync_pb::NigoriSpecifics* nigori) const {
334 nigori->set_encrypt_everything(encrypt_everything_);
335 nigori->set_encrypt_bookmarks(
336 encrypted_types_.count(syncable::BOOKMARKS) > 0);
337 nigori->set_encrypt_preferences(
338 encrypted_types_.count(syncable::PREFERENCES) > 0);
339 nigori->set_encrypt_autofill_profile(
340 encrypted_types_.count(syncable::AUTOFILL_PROFILE) > 0);
341 nigori->set_encrypt_autofill(encrypted_types_.count(syncable::AUTOFILL) > 0);
342 nigori->set_encrypt_themes(encrypted_types_.count(syncable::THEMES) > 0);
343 nigori->set_encrypt_typed_urls(
344 encrypted_types_.count(syncable::TYPED_URLS) > 0);
345 nigori->set_encrypt_extension_settings(
346 encrypted_types_.count(syncable::EXTENSION_SETTINGS) > 0);
347 nigori->set_encrypt_extensions(
348 encrypted_types_.count(syncable::EXTENSIONS) > 0);
349 nigori->set_encrypt_search_engines(
350 encrypted_types_.count(syncable::SEARCH_ENGINES) > 0);
351 nigori->set_encrypt_sessions(encrypted_types_.count(syncable::SESSIONS) > 0);
352 nigori->set_encrypt_app_settings(
353 encrypted_types_.count(syncable::APP_SETTINGS) > 0);
354 nigori->set_encrypt_apps(encrypted_types_.count(syncable::APPS) > 0);
355 nigori->set_encrypt_app_notifications(
356 encrypted_types_.count(syncable::APP_NOTIFICATIONS) > 0);
357 }
358
359 void Cryptographer::set_encrypt_everything() {
360 if (encrypt_everything_) {
361 DCHECK(encrypted_types_ == syncable::GetAllRealModelTypes());
362 return;
363 }
364 encrypt_everything_ = true;
365 // Change |encrypted_types_| directly to avoid sending more than one
366 // notification.
367 encrypted_types_ = syncable::GetAllRealModelTypes();
368 EmitEncryptedTypesChangedNotification();
369 }
370
371 bool Cryptographer::encrypt_everything() const {
372 return encrypt_everything_;
373 }
374
375 syncable::ModelTypeSet Cryptographer::GetEncryptedTypes() const {
376 return encrypted_types_;
377 }
378
379 void Cryptographer::SetEncryptedTypesForTest(
380 const syncable::ModelTypeSet& encrypted_types) {
381 SetEncryptedTypes(encrypted_types);
382 }
383
384 void Cryptographer::SetEncryptedTypes(
385 const syncable::ModelTypeSet& encrypted_types) {
386 if (encrypted_types_ == encrypted_types) {
387 return;
388 }
389 encrypted_types_ = encrypted_types;
390 EmitEncryptedTypesChangedNotification();
391 }
392
393 void Cryptographer::EmitEncryptedTypesChangedNotification() {
394 FOR_EACH_OBSERVER(
395 Observer, observers_,
396 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
397 }
398
399 void Cryptographer::InstallKeys(const std::string& default_key_name,
400 const sync_pb::NigoriKeyBag& bag) {
401 int key_size = bag.key_size();
402 for (int i = 0; i < key_size; ++i) {
403 const sync_pb::NigoriKey key = bag.key(i);
404 // Only use this key if we don't already know about it.
405 if (nigoris_.end() == nigoris_.find(key.name())) {
406 scoped_ptr<Nigori> new_nigori(new Nigori);
407 if (!new_nigori->InitByImport(key.user_key(),
408 key.encryption_key(),
409 key.mac_key())) {
410 NOTREACHED();
411 continue;
412 }
413 nigoris_[key.name()] = make_linked_ptr(new_nigori.release());
414 }
415 }
416 DCHECK(nigoris_.end() != nigoris_.find(default_key_name));
417 default_nigori_ = &*nigoris_.find(default_key_name);
418 }
419
420 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698