OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "sync/util/cryptographer.h" | 5 #include "sync/util/cryptographer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "sync/protocol/nigori_specifics.pb.h" |
| 12 #include "sync/syncable/nigori_handler.h" |
11 #include "sync/util/encryptor.h" | 13 #include "sync/util/encryptor.h" |
12 | 14 |
13 namespace syncer { | 15 namespace syncer { |
14 | 16 |
15 const char kNigoriTag[] = "google_chrome_nigori"; | 17 const char kNigoriTag[] = "google_chrome_nigori"; |
16 | 18 |
17 // We name a particular Nigori instance (ie. a triplet consisting of a hostname, | 19 // We name a particular Nigori instance (ie. a triplet consisting of a hostname, |
18 // a username, and a password) by calling Permute on this string. Since the | 20 // a username, and a password) by calling Permute on this string. Since the |
19 // output of Permute is always the same for a given triplet, clients will always | 21 // output of Permute is always the same for a given triplet, clients will always |
20 // assign the same name to a particular triplet. | 22 // assign the same name to a particular triplet. |
21 const char kNigoriKeyName[] = "nigori-key"; | 23 const char kNigoriKeyName[] = "nigori-key"; |
22 | 24 |
23 Cryptographer::Observer::~Observer() {} | |
24 | |
25 Cryptographer::Cryptographer(Encryptor* encryptor) | 25 Cryptographer::Cryptographer(Encryptor* encryptor) |
26 : encryptor_(encryptor), | 26 : encryptor_(encryptor), |
27 default_nigori_(NULL), | 27 default_nigori_(NULL), |
28 keystore_nigori_(NULL), | 28 keystore_nigori_(NULL), |
29 encrypted_types_(SensitiveTypes()), | 29 nigori_node_handler_(NULL) { |
30 encrypt_everything_(false) { | |
31 DCHECK(encryptor); | 30 DCHECK(encryptor); |
32 } | 31 } |
33 | 32 |
34 Cryptographer::~Cryptographer() {} | 33 Cryptographer::~Cryptographer() {} |
35 | 34 |
36 void Cryptographer::AddObserver(Observer* observer) { | 35 void Cryptographer::SetNigoriHandler(syncable::NigoriHandler* delegate) { |
37 observers_.AddObserver(observer); | 36 nigori_node_handler_ = delegate; |
38 } | 37 } |
39 | 38 |
40 void Cryptographer::RemoveObserver(Observer* observer) { | 39 void Cryptographer::UpdateFromNigori(const sync_pb::NigoriSpecifics& nigori) { |
41 observers_.RemoveObserver(observer); | 40 nigori_node_handler_->UpdateFromNigori(nigori); |
42 } | 41 } |
43 | 42 |
| 43 ModelTypeSet Cryptographer::GetEncryptedTypes() const { |
| 44 return nigori_node_handler_->GetEncryptedTypes(); |
| 45 } |
| 46 |
| 47 void Cryptographer::UpdateNigoriFromEncryptedTypes( |
| 48 sync_pb::NigoriSpecifics* nigori) const { |
| 49 nigori_node_handler_->UpdateNigoriFromEncryptedTypes(nigori); |
| 50 } |
| 51 |
| 52 |
44 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { | 53 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { |
45 if (is_initialized()) { | 54 if (is_initialized()) { |
46 NOTREACHED(); | 55 NOTREACHED(); |
47 return; | 56 return; |
48 } | 57 } |
49 | 58 |
50 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | 59 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); |
51 if (nigori.get()) | 60 if (nigori.get()) |
52 AddKeyImpl(nigori.release(), false); | 61 AddKeyImpl(nigori.release(), false); |
53 } | 62 } |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 | 196 |
188 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { | 197 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { |
189 DCHECK(CanDecrypt(encrypted)); | 198 DCHECK(CanDecrypt(encrypted)); |
190 | 199 |
191 sync_pb::NigoriKeyBag bag; | 200 sync_pb::NigoriKeyBag bag; |
192 if (!Decrypt(encrypted, &bag)) | 201 if (!Decrypt(encrypted, &bag)) |
193 return; | 202 return; |
194 InstallKeyBag(bag); | 203 InstallKeyBag(bag); |
195 } | 204 } |
196 | 205 |
| 206 void Cryptographer::SetDefaultKey(std::string key_name) { |
| 207 DCHECK(nigoris_.end() != nigoris_.find(key_name)); |
| 208 default_nigori_ = &*nigoris_.find(key_name); |
| 209 } |
| 210 |
197 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { | 211 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { |
198 DCHECK(!CanDecrypt(encrypted)); | 212 DCHECK(!CanDecrypt(encrypted)); |
199 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); | 213 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); |
200 } | 214 } |
201 | 215 |
202 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { | 216 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { |
203 DCHECK(has_pending_keys()); | 217 DCHECK(has_pending_keys()); |
204 return *(pending_keys_.get()); | 218 return *(pending_keys_.get()); |
205 } | 219 } |
206 | 220 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 scoped_ptr<Nigori> nigori(new Nigori); | 318 scoped_ptr<Nigori> nigori(new Nigori); |
305 if (!nigori->InitByImport(key.user_key(), key.encryption_key(), | 319 if (!nigori->InitByImport(key.user_key(), key.encryption_key(), |
306 key.mac_key())) { | 320 key.mac_key())) { |
307 NOTREACHED(); | 321 NOTREACHED(); |
308 return NULL; | 322 return NULL; |
309 } | 323 } |
310 | 324 |
311 return nigori.release(); | 325 return nigori.release(); |
312 } | 326 } |
313 | 327 |
314 Cryptographer::UpdateResult Cryptographer::Update( | |
315 const sync_pb::NigoriSpecifics& nigori) { | |
316 UpdateEncryptedTypesFromNigori(nigori); | |
317 if (!nigori.encrypted().blob().empty()) { | |
318 if (CanDecrypt(nigori.encrypted())) { | |
319 InstallKeys(nigori.encrypted()); | |
320 // We only update the default passphrase if this was a new explicit | |
321 // passphrase. Else, since it was decryptable, it must not have been a new | |
322 // key. | |
323 if (nigori.using_explicit_passphrase()) { | |
324 std::string new_default_key_name = nigori.encrypted().key_name(); | |
325 DCHECK(nigoris_.end() != nigoris_.find(new_default_key_name)); | |
326 default_nigori_ = &*nigoris_.find(new_default_key_name); | |
327 } | |
328 return Cryptographer::SUCCESS; | |
329 } else { | |
330 SetPendingKeys(nigori.encrypted()); | |
331 return Cryptographer::NEEDS_PASSPHRASE; | |
332 } | |
333 } | |
334 return Cryptographer::SUCCESS; | |
335 } | |
336 | |
337 bool Cryptographer::SetKeystoreKey(const std::string& keystore_key) { | 328 bool Cryptographer::SetKeystoreKey(const std::string& keystore_key) { |
338 if (keystore_key.empty()) | 329 if (keystore_key.empty()) |
339 return false; | 330 return false; |
340 KeyParams params = {"localhost", "dummy", keystore_key}; | 331 KeyParams params = {"localhost", "dummy", keystore_key}; |
341 | 332 |
342 // Create the new Nigori and make it the default keystore encryptor. | 333 // Create the new Nigori and make it the default keystore encryptor. |
343 scoped_ptr<Nigori> nigori(new Nigori); | 334 scoped_ptr<Nigori> nigori(new Nigori); |
344 if (!nigori->InitByDerivation(params.hostname, | 335 if (!nigori->InitByDerivation(params.hostname, |
345 params.username, | 336 params.username, |
346 params.password)) { | 337 params.password)) { |
347 NOTREACHED(); // Invalid username or password. | 338 NOTREACHED(); // Invalid username or password. |
348 return false; | 339 return false; |
349 } | 340 } |
350 | 341 |
351 return AddKeyImpl(nigori.release(), true); | 342 return AddKeyImpl(nigori.release(), true); |
352 } | 343 } |
353 | 344 |
354 bool Cryptographer::HasKeystoreKey() const { | 345 bool Cryptographer::HasKeystoreKey() const { |
355 return keystore_nigori_ != NULL; | 346 return keystore_nigori_ != NULL; |
356 } | 347 } |
357 | 348 |
358 // Static | |
359 ModelTypeSet Cryptographer::SensitiveTypes() { | |
360 // Both of these have their own encryption schemes, but we include them | |
361 // anyways. | |
362 ModelTypeSet types; | |
363 types.Put(PASSWORDS); | |
364 types.Put(NIGORI); | |
365 return types; | |
366 } | |
367 | |
368 void Cryptographer::UpdateEncryptedTypesFromNigori( | |
369 const sync_pb::NigoriSpecifics& nigori) { | |
370 if (nigori.encrypt_everything()) { | |
371 set_encrypt_everything(); | |
372 return; | |
373 } | |
374 | |
375 ModelTypeSet encrypted_types(SensitiveTypes()); | |
376 if (nigori.encrypt_bookmarks()) | |
377 encrypted_types.Put(BOOKMARKS); | |
378 if (nigori.encrypt_preferences()) | |
379 encrypted_types.Put(PREFERENCES); | |
380 if (nigori.encrypt_autofill_profile()) | |
381 encrypted_types.Put(AUTOFILL_PROFILE); | |
382 if (nigori.encrypt_autofill()) | |
383 encrypted_types.Put(AUTOFILL); | |
384 if (nigori.encrypt_themes()) | |
385 encrypted_types.Put(THEMES); | |
386 if (nigori.encrypt_typed_urls()) | |
387 encrypted_types.Put(TYPED_URLS); | |
388 if (nigori.encrypt_extension_settings()) | |
389 encrypted_types.Put(EXTENSION_SETTINGS); | |
390 if (nigori.encrypt_extensions()) | |
391 encrypted_types.Put(EXTENSIONS); | |
392 if (nigori.encrypt_search_engines()) | |
393 encrypted_types.Put(SEARCH_ENGINES); | |
394 if (nigori.encrypt_sessions()) | |
395 encrypted_types.Put(SESSIONS); | |
396 if (nigori.encrypt_app_settings()) | |
397 encrypted_types.Put(APP_SETTINGS); | |
398 if (nigori.encrypt_apps()) | |
399 encrypted_types.Put(APPS); | |
400 if (nigori.encrypt_app_notifications()) | |
401 encrypted_types.Put(APP_NOTIFICATIONS); | |
402 | |
403 // Note: the initial version with encryption did not support the | |
404 // encrypt_everything field. If anything more than the sensitive types were | |
405 // encrypted, it meant we were encrypting everything. | |
406 if (!nigori.has_encrypt_everything() && | |
407 !Difference(encrypted_types, SensitiveTypes()).Empty()) { | |
408 set_encrypt_everything(); | |
409 return; | |
410 } | |
411 | |
412 MergeEncryptedTypes(encrypted_types); | |
413 } | |
414 | |
415 void Cryptographer::UpdateNigoriFromEncryptedTypes( | |
416 sync_pb::NigoriSpecifics* nigori) const { | |
417 nigori->set_encrypt_everything(encrypt_everything_); | |
418 nigori->set_encrypt_bookmarks( | |
419 encrypted_types_.Has(BOOKMARKS)); | |
420 nigori->set_encrypt_preferences( | |
421 encrypted_types_.Has(PREFERENCES)); | |
422 nigori->set_encrypt_autofill_profile( | |
423 encrypted_types_.Has(AUTOFILL_PROFILE)); | |
424 nigori->set_encrypt_autofill(encrypted_types_.Has(AUTOFILL)); | |
425 nigori->set_encrypt_themes(encrypted_types_.Has(THEMES)); | |
426 nigori->set_encrypt_typed_urls( | |
427 encrypted_types_.Has(TYPED_URLS)); | |
428 nigori->set_encrypt_extension_settings( | |
429 encrypted_types_.Has(EXTENSION_SETTINGS)); | |
430 nigori->set_encrypt_extensions( | |
431 encrypted_types_.Has(EXTENSIONS)); | |
432 nigori->set_encrypt_search_engines( | |
433 encrypted_types_.Has(SEARCH_ENGINES)); | |
434 nigori->set_encrypt_sessions(encrypted_types_.Has(SESSIONS)); | |
435 nigori->set_encrypt_app_settings( | |
436 encrypted_types_.Has(APP_SETTINGS)); | |
437 nigori->set_encrypt_apps(encrypted_types_.Has(APPS)); | |
438 nigori->set_encrypt_app_notifications( | |
439 encrypted_types_.Has(APP_NOTIFICATIONS)); | |
440 } | |
441 | |
442 void Cryptographer::set_encrypt_everything() { | |
443 if (encrypt_everything_) { | |
444 DCHECK(encrypted_types_.Equals(ModelTypeSet::All())); | |
445 return; | |
446 } | |
447 encrypt_everything_ = true; | |
448 // Change |encrypted_types_| directly to avoid sending more than one | |
449 // notification. | |
450 encrypted_types_ = ModelTypeSet::All(); | |
451 EmitEncryptedTypesChangedNotification(); | |
452 } | |
453 | |
454 bool Cryptographer::encrypt_everything() const { | |
455 return encrypt_everything_; | |
456 } | |
457 | |
458 ModelTypeSet Cryptographer::GetEncryptedTypes() const { | |
459 return encrypted_types_; | |
460 } | |
461 | |
462 void Cryptographer::MergeEncryptedTypesForTest(ModelTypeSet encrypted_types) { | |
463 MergeEncryptedTypes(encrypted_types); | |
464 } | |
465 | |
466 void Cryptographer::MergeEncryptedTypes(ModelTypeSet encrypted_types) { | |
467 if (encrypted_types_.HasAll(encrypted_types)) { | |
468 return; | |
469 } | |
470 encrypted_types_ = encrypted_types; | |
471 EmitEncryptedTypesChangedNotification(); | |
472 } | |
473 | |
474 void Cryptographer::EmitEncryptedTypesChangedNotification() { | |
475 FOR_EACH_OBSERVER( | |
476 Observer, observers_, | |
477 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_)); | |
478 } | |
479 | |
480 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { | 349 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { |
481 int key_size = bag.key_size(); | 350 int key_size = bag.key_size(); |
482 for (int i = 0; i < key_size; ++i) { | 351 for (int i = 0; i < key_size; ++i) { |
483 const sync_pb::NigoriKey key = bag.key(i); | 352 const sync_pb::NigoriKey key = bag.key(i); |
484 // Only use this key if we don't already know about it. | 353 // Only use this key if we don't already know about it. |
485 if (nigoris_.end() == nigoris_.find(key.name())) { | 354 if (nigoris_.end() == nigoris_.find(key.name())) { |
486 scoped_ptr<Nigori> new_nigori(new Nigori); | 355 scoped_ptr<Nigori> new_nigori(new Nigori); |
487 if (!new_nigori->InitByImport(key.user_key(), | 356 if (!new_nigori->InitByImport(key.user_key(), |
488 key.encryption_key(), | 357 key.encryption_key(), |
489 key.mac_key())) { | 358 key.mac_key())) { |
490 NOTREACHED(); | 359 NOTREACHED(); |
491 continue; | 360 continue; |
492 } | 361 } |
493 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); | 362 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); |
494 } | 363 } |
495 } | 364 } |
496 } | 365 } |
497 | 366 |
498 } // namespace syncer | 367 } // namespace syncer |
OLD | NEW |