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

Side by Side Diff: chrome/browser/sync/internal_api/write_node.cc

Issue 8759019: [Sync] Add intelligent re-encryption support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase again Created 9 years 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 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 "chrome/browser/sync/internal_api/write_node.h" 5 #include "chrome/browser/sync/internal_api/write_node.h"
6 6
7 #include "base/json/json_writer.h" 7 #include "base/json/json_writer.h"
8 #include "base/utf_string_conversions.h" 8 #include "base/utf_string_conversions.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "chrome/browser/sync/engine/nigori_util.h" 10 #include "chrome/browser/sync/engine/nigori_util.h"
(...skipping 20 matching lines...) Expand all
31 namespace sync_api { 31 namespace sync_api {
32 32
33 static const char kDefaultNameForNewNodes[] = " "; 33 static const char kDefaultNameForNewNodes[] = " ";
34 34
35 bool WriteNode::UpdateEntryWithEncryption( 35 bool WriteNode::UpdateEntryWithEncryption(
36 browser_sync::Cryptographer* cryptographer, 36 browser_sync::Cryptographer* cryptographer,
37 const sync_pb::EntitySpecifics& new_specifics, 37 const sync_pb::EntitySpecifics& new_specifics,
38 syncable::MutableEntry* entry) { 38 syncable::MutableEntry* entry) {
39 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(new_specifics); 39 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(new_specifics);
40 DCHECK_GE(type, syncable::FIRST_REAL_MODEL_TYPE); 40 DCHECK_GE(type, syncable::FIRST_REAL_MODEL_TYPE);
41 const sync_pb::EntitySpecifics& old_specifics = entry->Get(SPECIFICS);
41 const syncable::ModelTypeSet encrypted_types = 42 const syncable::ModelTypeSet encrypted_types =
42 cryptographer->GetEncryptedTypes(); 43 cryptographer->GetEncryptedTypes();
43 sync_pb::EntitySpecifics generated_specifics; 44 sync_pb::EntitySpecifics generated_specifics;
44 if (!SpecificsNeedsEncryption(encrypted_types, new_specifics) || 45 if (!SpecificsNeedsEncryption(encrypted_types, new_specifics) ||
45 !cryptographer->is_initialized()) { 46 !cryptographer->is_initialized()) {
46 // No encryption required or we are unable to encrypt. 47 // No encryption required or we are unable to encrypt.
47 generated_specifics.CopyFrom(new_specifics); 48 generated_specifics.CopyFrom(new_specifics);
48 } else { 49 } else {
49 // Encrypt new_specifics into generated_specifics. 50 // Encrypt new_specifics into generated_specifics.
50 if (VLOG_IS_ON(2)) { 51 if (VLOG_IS_ON(2)) {
51 scoped_ptr<DictionaryValue> value(entry->ToValue()); 52 scoped_ptr<DictionaryValue> value(entry->ToValue());
52 std::string info; 53 std::string info;
53 base::JSONWriter::Write(value.get(), true, &info); 54 base::JSONWriter::Write(value.get(), true, &info);
54 DVLOG(2) << "Encrypting specifics of type " 55 DVLOG(2) << "Encrypting specifics of type "
55 << syncable::ModelTypeToString(type) 56 << syncable::ModelTypeToString(type)
56 << " with content: " 57 << " with content: "
57 << info; 58 << info;
58 } 59 }
59 syncable::AddDefaultExtensionValue(type, &generated_specifics); 60 // Only copy over the old specifics if it is of the right type and already
61 // encrypted. The first time we encrypt a node we start from scratch, hence
62 // removing all the unencrypted data, but from then on we only want to
63 // update the node if the data changes or the encryption key changes.
64 if (syncable::GetModelTypeFromSpecifics(old_specifics) == type &&
65 old_specifics.has_encrypted()) {
66 generated_specifics.CopyFrom(old_specifics);
67 } else {
68 syncable::AddDefaultExtensionValue(type, &generated_specifics);
69 }
70 // Does not change anything if underlying encrypted blob was already up
71 // to date and encrypted with the default key.
60 if (!cryptographer->Encrypt(new_specifics, 72 if (!cryptographer->Encrypt(new_specifics,
61 generated_specifics.mutable_encrypted())) { 73 generated_specifics.mutable_encrypted())) {
62 NOTREACHED() << "Could not encrypt data for node of type " 74 NOTREACHED() << "Could not encrypt data for node of type "
63 << syncable::ModelTypeToString(type); 75 << syncable::ModelTypeToString(type);
64 return false; 76 return false;
65 } 77 }
66 } 78 }
67 79
68 const sync_pb::EntitySpecifics& old_specifics = entry->Get(SPECIFICS); 80 // It's possible this entry was encrypted but didn't properly overwrite the
69 if (AreSpecificsEqual(cryptographer, old_specifics, generated_specifics) && 81 // non_unique_name (see crbug.com/96314).
70 (entry->Get(syncable::NON_UNIQUE_NAME) == kEncryptedString || 82 bool encrypted_without_overwriting_name = (old_specifics.has_encrypted() &&
71 !generated_specifics.has_encrypted())) { 83 entry->Get(syncable::NON_UNIQUE_NAME) != kEncryptedString);
72 // Even if the data is the same but the old specifics are encrypted with an 84
73 // old key, we should go ahead and re-encrypt with the new key. 85 // If we're encrypted but the name wasn't overwritten properly we still want
74 if ((!old_specifics.has_encrypted() && 86 // to rewrite the entry, irrespective of whether the specifics match.
75 !generated_specifics.has_encrypted()) || 87 if (!encrypted_without_overwriting_name &&
76 cryptographer->CanDecryptUsingDefaultKey(old_specifics.encrypted())) { 88 old_specifics.SerializeAsString() ==
77 DVLOG(2) << "Specifics of type " << syncable::ModelTypeToString(type) 89 generated_specifics.SerializeAsString()) {
78 << " already match, dropping change."; 90 DVLOG(2) << "Specifics of type " << syncable::ModelTypeToString(type)
79 return true; 91 << " already match, dropping change.";
80 } 92 return true;
81 // TODO(zea): Add some way to keep track of how often we're reencrypting
82 // because of a passphrase change.
83 } 93 }
84 94
85 if (generated_specifics.has_encrypted()) { 95 if (generated_specifics.has_encrypted()) {
86 // Overwrite the possibly sensitive non-specifics data. 96 // Overwrite the possibly sensitive non-specifics data.
87 entry->Put(syncable::NON_UNIQUE_NAME, kEncryptedString); 97 entry->Put(syncable::NON_UNIQUE_NAME, kEncryptedString);
88 // For bookmarks we actually put bogus data into the unencrypted specifics, 98 // For bookmarks we actually put bogus data into the unencrypted specifics,
89 // else the server will try to do it for us. 99 // else the server will try to do it for us.
90 if (type == syncable::BOOKMARKS) { 100 if (type == syncable::BOOKMARKS) {
91 sync_pb::BookmarkSpecifics* bookmark_specifics = 101 sync_pb::BookmarkSpecifics* bookmark_specifics =
92 generated_specifics.MutableExtension(sync_pb::bookmark); 102 generated_specifics.MutableExtension(sync_pb::bookmark);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value); 188 entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value);
179 SetEntitySpecifics(entity_specifics); 189 SetEntitySpecifics(entity_specifics);
180 } 190 }
181 191
182 void WriteNode::SetPasswordSpecifics( 192 void WriteNode::SetPasswordSpecifics(
183 const sync_pb::PasswordSpecificsData& data) { 193 const sync_pb::PasswordSpecificsData& data) {
184 DCHECK_EQ(syncable::PASSWORDS, GetModelType()); 194 DCHECK_EQ(syncable::PASSWORDS, GetModelType());
185 195
186 Cryptographer* cryptographer = GetTransaction()->GetCryptographer(); 196 Cryptographer* cryptographer = GetTransaction()->GetCryptographer();
187 197
188 // Idempotency check to prevent unnecessary syncing: if the plaintexts match
189 // and the old ciphertext is encrypted with the most current key, there's
190 // nothing to do here. Because each encryption is seeded with a different
191 // random value, checking for equivalence post-encryption doesn't suffice.
192 const sync_pb::EncryptedData& old_ciphertext =
193 GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::password).encrypted();
194 scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext(
195 DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer));
196 if (old_plaintext.get() &&
197 old_plaintext->SerializeAsString() == data.SerializeAsString() &&
198 cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) {
199 return;
200 }
201
202 sync_pb::PasswordSpecifics new_value; 198 sync_pb::PasswordSpecifics new_value;
203 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) { 199 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) {
204 NOTREACHED() << "Failed to encrypt password, possibly due to sync node " 200 NOTREACHED() << "Failed to encrypt password, possibly due to sync node "
205 << "corruption"; 201 << "corruption";
206 return; 202 return;
207 } 203 }
208 204
209 sync_pb::EntitySpecifics entity_specifics; 205 sync_pb::EntitySpecifics entity_specifics;
210 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); 206 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
211 SetEntitySpecifics(entity_specifics); 207 SetEntitySpecifics(entity_specifics);
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics(); 515 sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
520 new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size()); 516 new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size());
521 SetBookmarkSpecifics(new_value); 517 SetBookmarkSpecifics(new_value);
522 } 518 }
523 519
524 void WriteNode::MarkForSyncing() { 520 void WriteNode::MarkForSyncing() {
525 syncable::MarkForSyncing(entry_); 521 syncable::MarkForSyncing(entry_);
526 } 522 }
527 523
528 } // namespace sync_api 524 } // namespace sync_api
OLDNEW
« no previous file with comments | « chrome/browser/sync/internal_api/syncapi_unittest.cc ('k') | chrome/browser/sync/util/cryptographer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698