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

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

Powered by Google App Engine
This is Rietveld 408576698