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

Side by Side Diff: sync/internal_api/sync_encryption_handler_impl.cc

Issue 10827266: [Sync] Add SyncEncryptionHandler (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months 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) 2012 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 "sync/internal_api/sync_encryption_handler_impl.h"
6
7 #include <queue>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/message_loop.h"
12 #include "base/tracked_objects.h"
13 #include "base/metrics/histogram.h"
14 #include "sync/internal_api/public/read_node.h"
15 #include "sync/internal_api/public/read_transaction.h"
16 #include "sync/internal_api/public/user_share.h"
17 #include "sync/internal_api/public/util/experiments.h"
18 #include "sync/internal_api/public/write_node.h"
19 #include "sync/internal_api/public/write_transaction.h"
20 #include "sync/protocol/encryption.pb.h"
21 #include "sync/protocol/nigori_specifics.pb.h"
22 #include "sync/syncable/entry.h"
23 #include "sync/syncable/nigori_util.h"
24 #include "sync/util/cryptographer.h"
25
26 namespace syncer {
27
28 namespace {
29 // The maximum number of times we will automatically overwrite the nigori node
30 // because the encryption keys don't match (per chrome instantiation).
31 static const int kNigoriOverwriteLimit = 10;
32 }
33
34 SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl(
35 UserShare* user_share,
36 Cryptographer* cryptographer)
37 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
38 user_share_(user_share),
39 cryptographer_(cryptographer),
40 encrypted_types_(SensitiveTypes()),
41 encrypt_everything_(false),
42 explicit_passphrase_(false),
43 nigori_overwrite_count_(0) {
44 }
45
46 SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {}
47
48 void SyncEncryptionHandlerImpl::ReloadNigori() {
49 WriteTransaction trans(FROM_HERE, user_share_);
50 WriteNode node(&trans);
51 Cryptographer* cryptographer = trans.GetCryptographer();
52 cryptographer_ = cryptographer;
53
54 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
55 return;
56 }
57 if (!ApplyNigoriUpdate(node.GetNigoriSpecifics(), cryptographer))
58 WriteEncryptionStateToNigori(&trans);
59
60 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
61 OnCryptographerStateChanged(cryptographer));
62
63 if (cryptographer->is_ready())
64 ReEncryptEverything(&trans);
65 }
66
67 // Note: this is called from within a syncable transaction, so we need to post
68 // tasks if we want to do any work that creates a new sync_api transaction.
69 void SyncEncryptionHandlerImpl::UpdateFromNigori(
70 const sync_pb::NigoriSpecifics& nigori) {
71 if (!ApplyNigoriUpdate(nigori, cryptographer_)) {
72 MessageLoop::current()->PostTask(
73 FROM_HERE,
74 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori,
75 weak_ptr_factory_.GetWeakPtr()));
76 }
77
78 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
79 OnCryptographerStateChanged(cryptographer_));
80 }
81
82 void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) {
83 observers_.AddObserver(observer);
84 }
85
86 void SyncEncryptionHandlerImpl::RemoveObserver(Observer* observer) {
87 observers_.RemoveObserver(observer);
88 }
89
90 void SyncEncryptionHandlerImpl::SetEncryptionPassphrase(
91 const std::string& passphrase,
92 bool is_explicit) {
93 // We do not accept empty passphrases.
94 if (passphrase.empty()) {
95 NOTREACHED() << "Cannot encrypt with an empty passphrase.";
96 return;
97 }
98
99 // All accesses to the cryptographer are protected by a transaction.
100 WriteTransaction trans(FROM_HERE, user_share_);
101 Cryptographer* cryptographer = trans.GetCryptographer();
102 KeyParams key_params = {"localhost", "dummy", passphrase};
103 WriteNode node(&trans);
104 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
105 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
106 NOTREACHED();
107 return;
108 }
109
110 bool nigori_has_explicit_passphrase =
111 node.GetNigoriSpecifics().using_explicit_passphrase();
112 std::string bootstrap_token;
113 sync_pb::EncryptedData pending_keys;
114 if (cryptographer->has_pending_keys())
115 pending_keys = cryptographer->GetPendingKeys();
116 bool success = false;
117
118
119 // There are six cases to handle here:
120 // 1. The user has no pending keys and is setting their current GAIA password
121 // as the encryption passphrase. This happens either during first time sync
122 // with a clean profile, or after re-authenticating on a profile that was
123 // already signed in with the cryptographer ready.
124 // 2. The user has no pending keys, and is overwriting an (already provided)
125 // implicit passphrase with an explicit (custom) passphrase.
126 // 3. The user has pending keys for an explicit passphrase that is somehow set
127 // to their current GAIA passphrase.
128 // 4. The user has pending keys encrypted with their current GAIA passphrase
129 // and the caller passes in the current GAIA passphrase.
130 // 5. The user has pending keys encrypted with an older GAIA passphrase
131 // and the caller passes in the current GAIA passphrase.
132 // 6. The user has previously done encryption with an explicit passphrase.
133 // Furthermore, we enforce the fact that the bootstrap encryption token will
134 // always be derived from the newest GAIA password if the account is using
135 // an implicit passphrase (even if the data is encrypted with an old GAIA
136 // password). If the account is using an explicit (custom) passphrase, the
137 // bootstrap token will be derived from the most recently provided explicit
138 // passphrase (that was able to decrypt the data).
139 if (!nigori_has_explicit_passphrase) {
140 if (!cryptographer->has_pending_keys()) {
141 if (cryptographer->AddKey(key_params)) {
142 // Case 1 and 2. We set a new GAIA passphrase when there are no pending
143 // keys (1), or overwriting an implicit passphrase with a new explicit
144 // one (2) when there are no pending keys.
145 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" )
146 << " passphrase for encryption.";
147 cryptographer->GetBootstrapToken(&bootstrap_token);
148 success = true;
149 } else {
150 NOTREACHED() << "Failed to add key to cryptographer.";
151 success = false;
152 }
153 } else { // cryptographer->has_pending_keys() == true
154 if (is_explicit) {
155 // This can only happen if the nigori node is updated with a new
156 // implicit passphrase while a client is attempting to set a new custom
157 // passphrase (race condition).
158 DVLOG(1) << "Failing because an implicit passphrase is already set.";
159 success = false;
160 } else { // is_explicit == false
161 if (cryptographer->DecryptPendingKeys(key_params)) {
162 // Case 4. We successfully decrypted with the implicit GAIA passphrase
163 // passed in.
164 DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
165 cryptographer->GetBootstrapToken(&bootstrap_token);
166 success = true;
167 } else {
168 // Case 5. Encryption was done with an old GAIA password, but we were
169 // provided with the current GAIA password. We need to generate a new
170 // bootstrap token to preserve it. We build a temporary cryptographer
171 // to allow us to extract these params without polluting our current
172 // cryptographer.
173 DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
174 << "anyways as default passphrase and persisting via "
175 << "bootstrap token.";
176 Cryptographer temp_cryptographer(cryptographer->encryptor());
177 temp_cryptographer.AddKey(key_params);
178 temp_cryptographer.GetBootstrapToken(&bootstrap_token);
179 // We then set the new passphrase as the default passphrase of the
180 // real cryptographer, even though we have pending keys. This is safe,
181 // as although Cryptographer::is_initialized() will now be true,
182 // is_ready() will remain false due to having pending keys.
183 cryptographer->AddKey(key_params);
184 success = false;
185 }
186 } // is_explicit
187 } // cryptographer->has_pending_keys()
188 } else { // nigori_has_explicit_passphrase == true
189 // Case 6. We do not want to override a previously set explicit passphrase,
190 // so we return a failure.
191 DVLOG(1) << "Failing because an explicit passphrase is already set.";
192 success = false;
193 }
194
195 DVLOG_IF(1, !success)
196 << "Failure in SetEncryptionPassphrase; notifying and returning.";
197 DVLOG_IF(1, success)
198 << "Successfully set encryption passphrase; updating nigori and "
199 "reencrypting.";
200
201 FinishSetPassphrase(
202 success, bootstrap_token, is_explicit, &trans, &node);
203 }
204
205 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase(
206 const std::string& passphrase) {
207 // We do not accept empty passphrases.
208 if (passphrase.empty()) {
209 NOTREACHED() << "Cannot decrypt with an empty passphrase.";
210 return;
211 }
212
213 // All accesses to the cryptographer are protected by a transaction.
214 WriteTransaction trans(FROM_HERE, user_share_);
215 Cryptographer* cryptographer = trans.GetCryptographer();
216 KeyParams key_params = {"localhost", "dummy", passphrase};
217 WriteNode node(&trans);
218 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
219 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
220 NOTREACHED();
221 return;
222 }
223
224 if (!cryptographer->has_pending_keys()) {
225 // Note that this *can* happen in a rare situation where data is
226 // re-encrypted on another client while a SetDecryptionPassphrase() call is
227 // in-flight on this client. It is rare enough that we choose to do nothing.
228 NOTREACHED() << "Attempt to set decryption passphrase failed because there "
229 << "were no pending keys.";
230 return;
231 }
232
233 bool nigori_has_explicit_passphrase =
234 node.GetNigoriSpecifics().using_explicit_passphrase();
235 std::string bootstrap_token;
236 sync_pb::EncryptedData pending_keys;
237 pending_keys = cryptographer->GetPendingKeys();
238 bool success = false;
239
240 // There are three cases to handle here:
241 // 7. We're using the current GAIA password to decrypt the pending keys. This
242 // happens when signing in to an account with a previously set implicit
243 // passphrase, where the data is already encrypted with the newest GAIA
244 // password.
245 // 8. The user is providing an old GAIA password to decrypt the pending keys.
246 // In this case, the user is using an implicit passphrase, but has changed
247 // their password since they last encrypted their data, and therefore
248 // their current GAIA password was unable to decrypt the data. This will
249 // happen when the user is setting up a new profile with a previously
250 // encrypted account (after changing passwords).
251 // 9. The user is providing a previously set explicit passphrase to decrypt
252 // the pending keys.
253 if (!nigori_has_explicit_passphrase) {
254 if (cryptographer->is_initialized()) {
255 // We only want to change the default encryption key to the pending
256 // one if the pending keybag already contains the current default.
257 // This covers the case where a different client re-encrypted
258 // everything with a newer gaia passphrase (and hence the keybag
259 // contains keys from all previously used gaia passphrases).
260 // Otherwise, we're in a situation where the pending keys are
261 // encrypted with an old gaia passphrase, while the default is the
262 // current gaia passphrase. In that case, we preserve the default.
263 Cryptographer temp_cryptographer(cryptographer->encryptor());
264 temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
265 if (temp_cryptographer.DecryptPendingKeys(key_params)) {
266 // Check to see if the pending bag of keys contains the current
267 // default key.
268 sync_pb::EncryptedData encrypted;
269 cryptographer->GetKeys(&encrypted);
270 if (temp_cryptographer.CanDecrypt(encrypted)) {
271 DVLOG(1) << "Implicit user provided passphrase accepted for "
272 << "decryption, overwriting default.";
273 // Case 7. The pending keybag contains the current default. Go ahead
274 // and update the cryptographer, letting the default change.
275 cryptographer->DecryptPendingKeys(key_params);
276 cryptographer->GetBootstrapToken(&bootstrap_token);
277 success = true;
278 } else {
279 // Case 8. The pending keybag does not contain the current default
280 // encryption key. We decrypt the pending keys here, and in
281 // FinishSetPassphrase, re-encrypt everything with the current GAIA
282 // passphrase instead of the passphrase just provided by the user.
283 DVLOG(1) << "Implicit user provided passphrase accepted for "
284 << "decryption, restoring implicit internal passphrase "
285 << "as default.";
286 std::string bootstrap_token_from_current_key;
287 cryptographer->GetBootstrapToken(
288 &bootstrap_token_from_current_key);
289 cryptographer->DecryptPendingKeys(key_params);
290 // Overwrite the default from the pending keys.
291 cryptographer->AddKeyFromBootstrapToken(
292 bootstrap_token_from_current_key);
293 success = true;
294 }
295 } else { // !temp_cryptographer.DecryptPendingKeys(..)
296 DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
297 success = false;
298 } // temp_cryptographer.DecryptPendingKeys(...)
299 } else { // cryptographer->is_initialized() == false
300 if (cryptographer->DecryptPendingKeys(key_params)) {
301 // This can happpen in two cases:
302 // - First time sync on android, where we'll never have a
303 // !user_provided passphrase.
304 // - This is a restart for a client that lost their bootstrap token.
305 // In both cases, we should go ahead and initialize the cryptographer
306 // and persist the new bootstrap token.
307 //
308 // Note: at this point, we cannot distinguish between cases 7 and 8
309 // above. This user provided passphrase could be the current or the
310 // old. But, as long as we persist the token, there's nothing more
311 // we can do.
312 cryptographer->GetBootstrapToken(&bootstrap_token);
313 DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
314 << " cryptographer.";
315 success = true;
316 } else {
317 DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
318 success = false;
319 }
320 } // cryptographer->is_initialized()
321 } else { // nigori_has_explicit_passphrase == true
322 // Case 9. Encryption was done with an explicit passphrase, and we decrypt
323 // with the passphrase provided by the user.
324 if (cryptographer->DecryptPendingKeys(key_params)) {
325 DVLOG(1) << "Explicit passphrase accepted for decryption.";
326 cryptographer->GetBootstrapToken(&bootstrap_token);
327 success = true;
328 } else {
329 DVLOG(1) << "Explicit passphrase failed to decrypt.";
330 success = false;
331 }
332 } // nigori_has_explicit_passphrase
333
334 DVLOG_IF(1, !success)
335 << "Failure in SetDecryptionPassphrase; notifying and returning.";
336 DVLOG_IF(1, success)
337 << "Successfully set decryption passphrase; updating nigori and "
338 "reencrypting.";
339
340 FinishSetPassphrase(success,
341 bootstrap_token,
342 nigori_has_explicit_passphrase,
343 &trans,
344 &node);
345 }
346
347 void SyncEncryptionHandlerImpl::EnableEncryptEverything() {
348 if (encrypt_everything_) {
349 DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
350 return;
351 }
352 WriteTransaction trans(FROM_HERE, user_share_);
353 encrypt_everything_ = true;
354 // Change |encrypted_types_| directly to avoid sending more than one
355 // notification.
356 encrypted_types_ = ModelTypeSet::All();
357 FOR_EACH_OBSERVER(
358 Observer, observers_,
359 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
360 WriteEncryptionStateToNigori(&trans);
361 ReEncryptEverything(&trans);
362 }
363
364 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const {
365 ReadTransaction trans(FROM_HERE, user_share_);
366 return encrypt_everything_;
367 }
368
369 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes() const {
370 // Must be called from within a transaction, so no need to open a new one.
371 return encrypted_types_;
372 }
373
374 bool SyncEncryptionHandlerImpl::IsUsingExplicitPassphrase() const {
375 ReadTransaction trans(FROM_HERE, user_share_);
376 return explicit_passphrase_;
377 }
378
379 // This function iterates over all encrypted types. There are many scenarios in
380 // which data for some or all types is not currently available. In that case,
381 // the lookup of the root node will fail and we will skip encryption for that
382 // type.
383 void SyncEncryptionHandlerImpl::ReEncryptEverything(
384 WriteTransaction* trans) {
385 Cryptographer* cryptographer = trans->GetCryptographer();
386 if (!cryptographer->is_ready())
387 return;
388 ModelTypeSet encrypted_types = GetEncryptedTypes();
389 for (ModelTypeSet::Iterator iter = encrypted_types.First();
390 iter.Good(); iter.Inc()) {
391 if (iter.Get() == PASSWORDS || iter.Get() == NIGORI)
392 continue; // These types handle encryption differently.
393
394 ReadNode type_root(trans);
395 std::string tag = ModelTypeToRootTag(iter.Get());
396 if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK)
397 continue; // Don't try to reencrypt if the type's data is unavailable.
398
399 // Iterate through all children of this datatype.
400 std::queue<int64> to_visit;
401 int64 child_id = type_root.GetFirstChildId();
402 to_visit.push(child_id);
403 while (!to_visit.empty()) {
404 child_id = to_visit.front();
405 to_visit.pop();
406 if (child_id == kInvalidId)
407 continue;
408
409 WriteNode child(trans);
410 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
411 NOTREACHED();
412 continue;
413 }
414 if (child.GetIsFolder()) {
415 to_visit.push(child.GetFirstChildId());
416 }
417 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
418 // Rewrite the specifics of the node with encrypted data if necessary
419 // (only rewrite the non-unique folders).
420 child.ResetFromSpecifics();
421 }
422 to_visit.push(child.GetSuccessorId());
423 }
424 }
425
426 // Passwords are encrypted with their own legacy scheme. Passwords are always
427 // encrypted so we don't need to check GetEncryptedTypes() here.
428 ReadNode passwords_root(trans);
429 std::string passwords_tag = ModelTypeToRootTag(PASSWORDS);
430 if (passwords_root.InitByTagLookup(passwords_tag) ==
431 BaseNode::INIT_OK) {
432 int64 child_id = passwords_root.GetFirstChildId();
433 while (child_id != kInvalidId) {
434 WriteNode child(trans);
435 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
436 NOTREACHED();
437 return;
438 }
439 child.SetPasswordSpecifics(child.GetPasswordSpecifics());
440 child_id = child.GetSuccessorId();
441 }
442 }
443
444 // NOTE: We notify from within a transaction.
445 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
446 OnEncryptionComplete());
447 }
448
449 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdate(
450 const sync_pb::NigoriSpecifics& nigori,
451 Cryptographer* cryptographer) {
452 bool encrypted_types_need_update = !UpdateEncryptedTypesFromNigori(nigori);
453 if (nigori.using_explicit_passphrase())
454 explicit_passphrase_ = true;
455
456 bool needs_new_keys = false;
457 if (!nigori.encrypted().blob().empty()) {
458 if (cryptographer->CanDecrypt(nigori.encrypted())) {
459 cryptographer->InstallKeys(nigori.encrypted());
460 // We only update the default passphrase if this was a new explicit
461 // passphrase. Else, since it was decryptable, it must not have been a new
462 // key.
463 if (nigori.using_explicit_passphrase()) {
464 cryptographer->SetDefaultKey(nigori.encrypted().key_name());
465 }
466
467 sync_pb::EncryptedData new_keys = nigori.encrypted();
468 if (!cryptographer->GetKeys(&new_keys))
469 NOTREACHED();
470
471 if (nigori.encrypted().SerializeAsString() !=
472 new_keys.SerializeAsString()) {
473 needs_new_keys = true;
474 }
475 } else {
476 cryptographer->SetPendingKeys(nigori.encrypted());
477 }
478 } else {
479 needs_new_keys = true;
480 }
481
482 // If we've completed a sync cycle and the cryptographer isn't ready
483 // yet, prompt the user for a passphrase.
484 if (cryptographer->has_pending_keys()) {
485 DVLOG(1) << "OnPassPhraseRequired Sent";
486 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
487 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
488 OnPassphraseRequired(REASON_DECRYPTION,
489 pending_keys));
490 } else if (!cryptographer->is_ready()) {
491 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
492 << "ready";
493 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
494 OnPassphraseRequired(REASON_ENCRYPTION,
495 sync_pb::EncryptedData()));
496 }
497
498 // Check if the current local state is stricter than the nigori state. If so,
499 // we need to update the nigori.
500 if (nigori.using_explicit_passphrase() != explicit_passphrase_ ||
501 nigori.encrypt_everything() != encrypt_everything_ ||
502 encrypted_types_need_update ||
503 needs_new_keys) {
504 return false;
505 }
506 return true;
507 }
508
509 void SyncEncryptionHandlerImpl::RewriteNigori() {
510 WriteTransaction trans(FROM_HERE, user_share_);
511 WriteEncryptionStateToNigori(&trans);
512 }
513
514 void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori(
515 WriteTransaction* trans) {
516 WriteNode nigori_node(trans);
517 if (!nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) {
518 // This can happen in tests that don't have nigori nodes.
519 return;
520 }
521 sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics();
522 Cryptographer* cryptographer = trans->GetCryptographer();
523 if (cryptographer->is_ready() &&
524 nigori_overwrite_count_ < kNigoriOverwriteLimit) {
525 // Does not modify the encrypted blob if the unencrypted data already
526 // matches what is about to be written.
527 sync_pb::EncryptedData original_keys = nigori.encrypted();
528 if (!cryptographer->GetKeys(nigori.mutable_encrypted()))
529 NOTREACHED();
530
531 if (nigori.encrypted().SerializeAsString() !=
532 original_keys.SerializeAsString()) {
533 // We've updated the nigori node's encryption keys. In order to prevent
534 // a possible looping of two clients constantly overwriting each other,
535 // we limit the absolute number of overwrites per client instantiation.
536 nigori_overwrite_count_++;
537 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites",
538 nigori_overwrite_count_);
539 }
540
541 // Note: we don't try to set using_explicit_passphrase here since if that
542 // is lost the user can always set it again. The main point is to preserve
543 // the encryption keys so all data remains decryptable.
544 }
545 UpdateNigoriFromEncryptedTypes(&nigori);
546
547 // If nothing has changed, this is a no-op.
548 nigori_node.SetNigoriSpecifics(nigori);
549 }
550
551 bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori(
552 const sync_pb::NigoriSpecifics& nigori) {
553 if (nigori.encrypt_everything()) {
554 if (!encrypt_everything_) {
555 encrypt_everything_ = true;
556 encrypted_types_ = ModelTypeSet::All();
557 FOR_EACH_OBSERVER(
558 Observer, observers_,
559 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
560 }
561 DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
562 return true;
563 }
564
565 ModelTypeSet encrypted_types(SensitiveTypes());
566 if (nigori.encrypt_bookmarks())
567 encrypted_types.Put(BOOKMARKS);
568 if (nigori.encrypt_preferences())
569 encrypted_types.Put(PREFERENCES);
570 if (nigori.encrypt_autofill_profile())
571 encrypted_types.Put(AUTOFILL_PROFILE);
572 if (nigori.encrypt_autofill())
573 encrypted_types.Put(AUTOFILL);
574 if (nigori.encrypt_themes())
575 encrypted_types.Put(THEMES);
576 if (nigori.encrypt_typed_urls())
577 encrypted_types.Put(TYPED_URLS);
578 if (nigori.encrypt_extension_settings())
579 encrypted_types.Put(EXTENSION_SETTINGS);
580 if (nigori.encrypt_extensions())
581 encrypted_types.Put(EXTENSIONS);
582 if (nigori.encrypt_search_engines())
583 encrypted_types.Put(SEARCH_ENGINES);
584 if (nigori.encrypt_sessions())
585 encrypted_types.Put(SESSIONS);
586 if (nigori.encrypt_app_settings())
587 encrypted_types.Put(APP_SETTINGS);
588 if (nigori.encrypt_apps())
589 encrypted_types.Put(APPS);
590 if (nigori.encrypt_app_notifications())
591 encrypted_types.Put(APP_NOTIFICATIONS);
592
593 // Note: the initial version with encryption did not support the
594 // encrypt_everything field. If anything more than the sensitive types were
595 // encrypted, it meant we were encrypting everything.
596 if (!nigori.has_encrypt_everything() &&
597 !Difference(encrypted_types, SensitiveTypes()).Empty()) {
598 if (!encrypt_everything_) {
599 encrypt_everything_ = true;
600 encrypted_types_ = ModelTypeSet::All();
601 FOR_EACH_OBSERVER(
602 Observer, observers_,
603 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
604 }
605 DCHECK(encrypted_types_.Equals(ModelTypeSet::All()));
606 return false;
607 }
608
609 MergeEncryptedTypes(encrypted_types);
610 if (!encrypted_types_.Equals(encrypted_types))
611 return false;
612 return true;
613 }
614
615 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes(
616 sync_pb::NigoriSpecifics* nigori) const {
617 syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_,
618 encrypt_everything_,
619 nigori);
620 }
621
622 void SyncEncryptionHandlerImpl::FinishSetPassphrase(
623 bool success,
624 const std::string& bootstrap_token,
625 bool is_explicit,
626 WriteTransaction* trans,
627 WriteNode* nigori_node) {
628 Cryptographer* cryptographer = trans->GetCryptographer();
629 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
630 OnCryptographerStateChanged(cryptographer));
631
632 // It's possible we need to change the bootstrap token even if we failed to
633 // set the passphrase (for example if we need to preserve the new GAIA
634 // passphrase).
635 if (!bootstrap_token.empty()) {
636 DVLOG(1) << "Bootstrap token updated.";
637 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
638 OnBootstrapTokenUpdated(bootstrap_token));
639 }
640
641 if (!success) {
642 if (cryptographer->is_ready()) {
643 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
644 << "was ready.";
645 } else if (cryptographer->has_pending_keys()) {
646 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
647 OnPassphraseRequired(REASON_DECRYPTION,
648 cryptographer->GetPendingKeys()));
649 } else {
650 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
651 OnPassphraseRequired(REASON_ENCRYPTION,
652 sync_pb::EncryptedData()));
653 }
654 return;
655 }
656
657 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_,
658 OnPassphraseAccepted());
659 DCHECK(cryptographer->is_ready());
660
661 // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't
662 // require messing with the Nigori node, because we can't set a passphrase
663 // until download conditions are met vs Cryptographer init. It seems like
664 // it's safe to defer this work.
665 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics());
666 // Does not modify specifics.encrypted() if the original decrypted data was
667 // the same.
668 if (!cryptographer->GetKeys(specifics.mutable_encrypted())) {
669 NOTREACHED();
670 return;
671 }
672 specifics.set_using_explicit_passphrase(is_explicit);
673 nigori_node->SetNigoriSpecifics(specifics);
674
675 // Does nothing if everything is already encrypted or the cryptographer has
676 // pending keys.
677 ReEncryptEverything(trans);
678 }
679
680 void SyncEncryptionHandlerImpl::MergeEncryptedTypes(
681 ModelTypeSet encrypted_types) {
682 if (encrypted_types_.HasAll(encrypted_types))
683 return;
684 encrypted_types_ = encrypted_types;
685 FOR_EACH_OBSERVER(
686 Observer, observers_,
687 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_));
688 }
689
690 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698