| 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/basictypes.h" |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 #include "sync/protocol/nigori_specifics.pb.h" | 12 #include "sync/protocol/nigori_specifics.pb.h" |
| 12 #include "sync/util/encryptor.h" | 13 #include "sync/util/encryptor.h" |
| 13 | 14 |
| 14 namespace syncer { | 15 namespace syncer { |
| 15 | 16 |
| 16 const char kNigoriTag[] = "google_chrome_nigori"; | 17 const char kNigoriTag[] = "google_chrome_nigori"; |
| 17 | 18 |
| 18 // 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, |
| 19 // 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 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 30 | 31 |
| 31 | 32 |
| 32 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { | 33 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { |
| 33 if (is_initialized()) { | 34 if (is_initialized()) { |
| 34 NOTREACHED(); | 35 NOTREACHED(); |
| 35 return; | 36 return; |
| 36 } | 37 } |
| 37 | 38 |
| 38 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | 39 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); |
| 39 if (nigori.get()) | 40 if (nigori.get()) |
| 40 AddKeyImpl(nigori.Pass()); | 41 AddKeyImpl(nigori.Pass(), true); |
| 41 } | 42 } |
| 42 | 43 |
| 43 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { | 44 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { |
| 44 return nigoris_.end() != nigoris_.find(data.key_name()); | 45 return nigoris_.end() != nigoris_.find(data.key_name()); |
| 45 } | 46 } |
| 46 | 47 |
| 47 bool Cryptographer::CanDecryptUsingDefaultKey( | 48 bool Cryptographer::CanDecryptUsingDefaultKey( |
| 48 const sync_pb::EncryptedData& data) const { | 49 const sync_pb::EncryptedData& data) const { |
| 49 return !default_nigori_name_.empty() && | 50 return !default_nigori_name_.empty() && |
| 50 data.key_name() == default_nigori_name_; | 51 data.key_name() == default_nigori_name_; |
| 51 } | 52 } |
| 52 | 53 |
| 53 bool Cryptographer::Encrypt( | 54 bool Cryptographer::Encrypt( |
| 54 const ::google::protobuf::MessageLite& message, | 55 const ::google::protobuf::MessageLite& message, |
| 55 sync_pb::EncryptedData* encrypted) const { | 56 sync_pb::EncryptedData* encrypted) const { |
| 56 DCHECK(encrypted); | 57 DCHECK(encrypted); |
| 57 if (default_nigori_name_.empty()) { | 58 if (default_nigori_name_.empty()) { |
| 58 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; | 59 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; |
| 59 return false; | 60 return false; |
| 60 } | 61 } |
| 61 NigoriMap::const_iterator default_nigori = | |
| 62 nigoris_.find(default_nigori_name_); | |
| 63 if (default_nigori == nigoris_.end()) { | |
| 64 LOG(ERROR) << "Corrupt default key."; | |
| 65 return false; | |
| 66 } | |
| 67 | 62 |
| 68 std::string serialized; | 63 std::string serialized; |
| 69 if (!message.SerializeToString(&serialized)) { | 64 if (!message.SerializeToString(&serialized)) { |
| 70 LOG(ERROR) << "Message is invalid/missing a required field."; | 65 LOG(ERROR) << "Message is invalid/missing a required field."; |
| 71 return false; | 66 return false; |
| 72 } | 67 } |
| 73 | 68 |
| 69 return EncryptString(serialized, encrypted); |
| 70 } |
| 71 |
| 72 bool Cryptographer::EncryptString( |
| 73 const std::string& serialized, |
| 74 sync_pb::EncryptedData* encrypted) const { |
| 74 if (CanDecryptUsingDefaultKey(*encrypted)) { | 75 if (CanDecryptUsingDefaultKey(*encrypted)) { |
| 75 const std::string& original_serialized = DecryptToString(*encrypted); | 76 const std::string& original_serialized = DecryptToString(*encrypted); |
| 76 if (original_serialized == serialized) { | 77 if (original_serialized == serialized) { |
| 77 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; | 78 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; |
| 78 return true; | 79 return true; |
| 79 } | 80 } |
| 80 } | 81 } |
| 81 | 82 |
| 83 NigoriMap::const_iterator default_nigori = |
| 84 nigoris_.find(default_nigori_name_); |
| 85 if (default_nigori == nigoris_.end()) { |
| 86 LOG(ERROR) << "Corrupt default key."; |
| 87 return false; |
| 88 } |
| 89 |
| 82 encrypted->set_key_name(default_nigori_name_); | 90 encrypted->set_key_name(default_nigori_name_); |
| 83 if (!default_nigori->second->Encrypt(serialized, | 91 if (!default_nigori->second->Encrypt(serialized, |
| 84 encrypted->mutable_blob())) { | 92 encrypted->mutable_blob())) { |
| 85 LOG(ERROR) << "Failed to encrypt data."; | 93 LOG(ERROR) << "Failed to encrypt data."; |
| 86 return false; | 94 return false; |
| 87 } | 95 } |
| 88 return true; | 96 return true; |
| 89 } | 97 } |
| 90 | 98 |
| 91 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, | 99 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 | 141 |
| 134 bool Cryptographer::AddKey(const KeyParams& params) { | 142 bool Cryptographer::AddKey(const KeyParams& params) { |
| 135 // Create the new Nigori and make it the default encryptor. | 143 // Create the new Nigori and make it the default encryptor. |
| 136 scoped_ptr<Nigori> nigori(new Nigori); | 144 scoped_ptr<Nigori> nigori(new Nigori); |
| 137 if (!nigori->InitByDerivation(params.hostname, | 145 if (!nigori->InitByDerivation(params.hostname, |
| 138 params.username, | 146 params.username, |
| 139 params.password)) { | 147 params.password)) { |
| 140 NOTREACHED(); // Invalid username or password. | 148 NOTREACHED(); // Invalid username or password. |
| 141 return false; | 149 return false; |
| 142 } | 150 } |
| 143 return AddKeyImpl(nigori.Pass()); | 151 return AddKeyImpl(nigori.Pass(), true); |
| 152 } |
| 153 |
| 154 bool Cryptographer::AddNonDefaultKey(const KeyParams& params) { |
| 155 DCHECK(is_initialized()); |
| 156 // Create the new Nigori and add it to the keybag. |
| 157 scoped_ptr<Nigori> nigori(new Nigori); |
| 158 if (!nigori->InitByDerivation(params.hostname, |
| 159 params.username, |
| 160 params.password)) { |
| 161 NOTREACHED(); // Invalid username or password. |
| 162 return false; |
| 163 } |
| 164 return AddKeyImpl(nigori.Pass(), false); |
| 144 } | 165 } |
| 145 | 166 |
| 146 bool Cryptographer::AddKeyFromBootstrapToken( | 167 bool Cryptographer::AddKeyFromBootstrapToken( |
| 147 const std::string restored_bootstrap_token) { | 168 const std::string restored_bootstrap_token) { |
| 148 // Create the new Nigori and make it the default encryptor. | 169 // Create the new Nigori and make it the default encryptor. |
| 149 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | 170 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); |
| 150 if (!nigori.get()) | 171 if (!nigori.get()) |
| 151 return false; | 172 return false; |
| 152 return AddKeyImpl(nigori.Pass()); | 173 return AddKeyImpl(nigori.Pass(), true); |
| 153 } | 174 } |
| 154 | 175 |
| 155 bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori) { | 176 bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori, |
| 177 bool set_as_default) { |
| 156 std::string name; | 178 std::string name; |
| 157 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { | 179 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { |
| 158 NOTREACHED(); | 180 NOTREACHED(); |
| 159 return false; | 181 return false; |
| 160 } | 182 } |
| 183 |
| 161 nigoris_[name] = make_linked_ptr(initialized_nigori.release()); | 184 nigoris_[name] = make_linked_ptr(initialized_nigori.release()); |
| 162 default_nigori_name_ = name; | 185 |
| 186 // Check if the key we just added can decrypt the pending keys and add them |
| 187 // too if so. |
| 188 if (pending_keys_.get() && CanDecrypt(*pending_keys_)) { |
| 189 sync_pb::NigoriKeyBag pending_bag; |
| 190 Decrypt(*pending_keys_, &pending_bag); |
| 191 InstallKeyBag(pending_bag); |
| 192 SetDefaultKey(pending_keys_->key_name()); |
| 193 pending_keys_.reset(); |
| 194 } |
| 195 |
| 196 // The just-added key takes priority over the pending keys as default. |
| 197 if (set_as_default) SetDefaultKey(name); |
| 163 return true; | 198 return true; |
| 164 } | 199 } |
| 165 | 200 |
| 166 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { | 201 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { |
| 167 DCHECK(CanDecrypt(encrypted)); | 202 DCHECK(CanDecrypt(encrypted)); |
| 168 | 203 |
| 169 sync_pb::NigoriKeyBag bag; | 204 sync_pb::NigoriKeyBag bag; |
| 170 if (!Decrypt(encrypted, &bag)) | 205 if (!Decrypt(encrypted, &bag)) |
| 171 return; | 206 return; |
| 172 InstallKeyBag(bag); | 207 InstallKeyBag(bag); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 key.encryption_key(), | 335 key.encryption_key(), |
| 301 key.mac_key())) { | 336 key.mac_key())) { |
| 302 NOTREACHED(); | 337 NOTREACHED(); |
| 303 continue; | 338 continue; |
| 304 } | 339 } |
| 305 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); | 340 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); |
| 306 } | 341 } |
| 307 } | 342 } |
| 308 } | 343 } |
| 309 | 344 |
| 345 bool Cryptographer::KeybagIsStale( |
| 346 const sync_pb::EncryptedData& encrypted_bag) const { |
| 347 if (!is_ready()) |
| 348 return false; |
| 349 if (encrypted_bag.blob().empty()) |
| 350 return true; |
| 351 if (!CanDecrypt(encrypted_bag)) |
| 352 return false; |
| 353 if (!CanDecryptUsingDefaultKey(encrypted_bag)) |
| 354 return true; |
| 355 sync_pb::NigoriKeyBag bag; |
| 356 if (!Decrypt(encrypted_bag, &bag)) { |
| 357 LOG(ERROR) << "Failed to decrypt keybag for stale check. " |
| 358 << "Assuming keybag is corrupted."; |
| 359 return true; |
| 360 } |
| 361 if (static_cast<size_t>(bag.key_size()) < nigoris_.size()) |
| 362 return true; |
| 363 return false; |
| 364 } |
| 365 |
| 310 } // namespace syncer | 366 } // namespace syncer |
| OLD | NEW |