| 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 "components/sync/base/cryptographer.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 |
| 8 #include <algorithm> | 9 #include <algorithm> |
| 9 #include <utility> | 10 #include <utility> |
| 10 | 11 |
| 11 #include "base/base64.h" | 12 #include "base/base64.h" |
| 12 #include "base/logging.h" | 13 #include "base/logging.h" |
| 13 #include "sync/protocol/nigori_specifics.pb.h" | 14 #include "components/sync/base/encryptor.h" |
| 14 #include "sync/util/encryptor.h" | 15 #include "components/sync/protocol/nigori_specifics.pb.h" |
| 15 | 16 |
| 16 namespace syncer { | 17 namespace syncer { |
| 17 | 18 |
| 18 const char kNigoriTag[] = "google_chrome_nigori"; | 19 const char kNigoriTag[] = "google_chrome_nigori"; |
| 19 | 20 |
| 20 // We name a particular Nigori instance (ie. a triplet consisting of a hostname, | 21 // We name a particular Nigori instance (ie. a triplet consisting of a hostname, |
| 21 // a username, and a password) by calling Permute on this string. Since the | 22 // a username, and a password) by calling Permute on this string. Since the |
| 22 // output of Permute is always the same for a given triplet, clients will always | 23 // output of Permute is always the same for a given triplet, clients will always |
| 23 // assign the same name to a particular triplet. | 24 // assign the same name to a particular triplet. |
| 24 const char kNigoriKeyName[] = "nigori-key"; | 25 const char kNigoriKeyName[] = "nigori-key"; |
| 25 | 26 |
| 26 Cryptographer::Cryptographer(Encryptor* encryptor) | 27 Cryptographer::Cryptographer(Encryptor* encryptor) : encryptor_(encryptor) { |
| 27 : encryptor_(encryptor) { | |
| 28 DCHECK(encryptor); | 28 DCHECK(encryptor); |
| 29 } | 29 } |
| 30 | 30 |
| 31 Cryptographer::Cryptographer(const Cryptographer& other) | 31 Cryptographer::Cryptographer(const Cryptographer& other) |
| 32 : encryptor_(other.encryptor_), | 32 : encryptor_(other.encryptor_), |
| 33 default_nigori_name_(other.default_nigori_name_) { | 33 default_nigori_name_(other.default_nigori_name_) { |
| 34 for (NigoriMap::const_iterator it = other.nigoris_.begin(); | 34 for (NigoriMap::const_iterator it = other.nigoris_.begin(); |
| 35 it != other.nigoris_.end(); | 35 it != other.nigoris_.end(); ++it) { |
| 36 ++it) { | |
| 37 std::string user_key, encryption_key, mac_key; | 36 std::string user_key, encryption_key, mac_key; |
| 38 it->second->ExportKeys(&user_key, &encryption_key, &mac_key); | 37 it->second->ExportKeys(&user_key, &encryption_key, &mac_key); |
| 39 linked_ptr<Nigori> nigori_copy(new Nigori()); | 38 linked_ptr<Nigori> nigori_copy(new Nigori()); |
| 40 nigori_copy->InitByImport(user_key, encryption_key, mac_key); | 39 nigori_copy->InitByImport(user_key, encryption_key, mac_key); |
| 41 nigoris_.insert(std::make_pair(it->first, nigori_copy)); | 40 nigoris_.insert(std::make_pair(it->first, nigori_copy)); |
| 42 } | 41 } |
| 43 | 42 |
| 44 if (other.pending_keys_) { | 43 if (other.pending_keys_) { |
| 45 pending_keys_.reset(new sync_pb::EncryptedData(*(other.pending_keys_))); | 44 pending_keys_.reset(new sync_pb::EncryptedData(*(other.pending_keys_))); |
| 46 } | 45 } |
| 47 } | 46 } |
| 48 | 47 |
| 49 Cryptographer::~Cryptographer() {} | 48 Cryptographer::~Cryptographer() {} |
| 50 | 49 |
| 51 | |
| 52 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { | 50 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { |
| 53 if (is_initialized()) { | 51 if (is_initialized()) { |
| 54 NOTREACHED(); | 52 NOTREACHED(); |
| 55 return; | 53 return; |
| 56 } | 54 } |
| 57 | 55 |
| 58 std::string serialized_nigori_key = | 56 std::string serialized_nigori_key = |
| 59 UnpackBootstrapToken(restored_bootstrap_token); | 57 UnpackBootstrapToken(restored_bootstrap_token); |
| 60 if (serialized_nigori_key.empty()) | 58 if (serialized_nigori_key.empty()) |
| 61 return; | 59 return; |
| 62 ImportNigoriKey(serialized_nigori_key); | 60 ImportNigoriKey(serialized_nigori_key); |
| 63 } | 61 } |
| 64 | 62 |
| 65 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { | 63 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { |
| 66 return nigoris_.end() != nigoris_.find(data.key_name()); | 64 return nigoris_.end() != nigoris_.find(data.key_name()); |
| 67 } | 65 } |
| 68 | 66 |
| 69 bool Cryptographer::CanDecryptUsingDefaultKey( | 67 bool Cryptographer::CanDecryptUsingDefaultKey( |
| 70 const sync_pb::EncryptedData& data) const { | 68 const sync_pb::EncryptedData& data) const { |
| 71 return !default_nigori_name_.empty() && | 69 return !default_nigori_name_.empty() && |
| 72 data.key_name() == default_nigori_name_; | 70 data.key_name() == default_nigori_name_; |
| 73 } | 71 } |
| 74 | 72 |
| 75 bool Cryptographer::Encrypt( | 73 bool Cryptographer::Encrypt(const ::google::protobuf::MessageLite& message, |
| 76 const ::google::protobuf::MessageLite& message, | 74 sync_pb::EncryptedData* encrypted) const { |
| 77 sync_pb::EncryptedData* encrypted) const { | |
| 78 DCHECK(encrypted); | 75 DCHECK(encrypted); |
| 79 if (default_nigori_name_.empty()) { | 76 if (default_nigori_name_.empty()) { |
| 80 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; | 77 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; |
| 81 return false; | 78 return false; |
| 82 } | 79 } |
| 83 | 80 |
| 84 std::string serialized; | 81 std::string serialized; |
| 85 if (!message.SerializeToString(&serialized)) { | 82 if (!message.SerializeToString(&serialized)) { |
| 86 LOG(ERROR) << "Message is invalid/missing a required field."; | 83 LOG(ERROR) << "Message is invalid/missing a required field."; |
| 87 return false; | 84 return false; |
| 88 } | 85 } |
| 89 | 86 |
| 90 return EncryptString(serialized, encrypted); | 87 return EncryptString(serialized, encrypted); |
| 91 } | 88 } |
| 92 | 89 |
| 93 bool Cryptographer::EncryptString( | 90 bool Cryptographer::EncryptString(const std::string& serialized, |
| 94 const std::string& serialized, | 91 sync_pb::EncryptedData* encrypted) const { |
| 95 sync_pb::EncryptedData* encrypted) const { | |
| 96 if (CanDecryptUsingDefaultKey(*encrypted)) { | 92 if (CanDecryptUsingDefaultKey(*encrypted)) { |
| 97 const std::string& original_serialized = DecryptToString(*encrypted); | 93 const std::string& original_serialized = DecryptToString(*encrypted); |
| 98 if (original_serialized == serialized) { | 94 if (original_serialized == serialized) { |
| 99 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; | 95 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; |
| 100 return true; | 96 return true; |
| 101 } | 97 } |
| 102 } | 98 } |
| 103 | 99 |
| 104 NigoriMap::const_iterator default_nigori = | 100 NigoriMap::const_iterator default_nigori = |
| 105 nigoris_.find(default_nigori_name_); | 101 nigoris_.find(default_nigori_name_); |
| 106 if (default_nigori == nigoris_.end()) { | 102 if (default_nigori == nigoris_.end()) { |
| 107 LOG(ERROR) << "Corrupt default key."; | 103 LOG(ERROR) << "Corrupt default key."; |
| 108 return false; | 104 return false; |
| 109 } | 105 } |
| 110 | 106 |
| 111 encrypted->set_key_name(default_nigori_name_); | 107 encrypted->set_key_name(default_nigori_name_); |
| 112 if (!default_nigori->second->Encrypt(serialized, | 108 if (!default_nigori->second->Encrypt(serialized, encrypted->mutable_blob())) { |
| 113 encrypted->mutable_blob())) { | |
| 114 LOG(ERROR) << "Failed to encrypt data."; | 109 LOG(ERROR) << "Failed to encrypt data."; |
| 115 return false; | 110 return false; |
| 116 } | 111 } |
| 117 return true; | 112 return true; |
| 118 } | 113 } |
| 119 | 114 |
| 120 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, | 115 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, |
| 121 ::google::protobuf::MessageLite* message) const { | 116 ::google::protobuf::MessageLite* message) const { |
| 122 DCHECK(message); | 117 DCHECK(message); |
| 123 std::string plaintext = DecryptToString(encrypted); | 118 std::string plaintext = DecryptToString(encrypted); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 146 DCHECK(encrypted); | 141 DCHECK(encrypted); |
| 147 DCHECK(!nigoris_.empty()); | 142 DCHECK(!nigoris_.empty()); |
| 148 | 143 |
| 149 // Create a bag of all the Nigori parameters we know about. | 144 // Create a bag of all the Nigori parameters we know about. |
| 150 sync_pb::NigoriKeyBag bag; | 145 sync_pb::NigoriKeyBag bag; |
| 151 for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end(); | 146 for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end(); |
| 152 ++it) { | 147 ++it) { |
| 153 const Nigori& nigori = *it->second; | 148 const Nigori& nigori = *it->second; |
| 154 sync_pb::NigoriKey* key = bag.add_key(); | 149 sync_pb::NigoriKey* key = bag.add_key(); |
| 155 key->set_name(it->first); | 150 key->set_name(it->first); |
| 156 nigori.ExportKeys(key->mutable_user_key(), | 151 nigori.ExportKeys(key->mutable_user_key(), key->mutable_encryption_key(), |
| 157 key->mutable_encryption_key(), | |
| 158 key->mutable_mac_key()); | 152 key->mutable_mac_key()); |
| 159 } | 153 } |
| 160 | 154 |
| 161 // Encrypt the bag with the default Nigori. | 155 // Encrypt the bag with the default Nigori. |
| 162 return Encrypt(bag, encrypted); | 156 return Encrypt(bag, encrypted); |
| 163 } | 157 } |
| 164 | 158 |
| 165 bool Cryptographer::AddKey(const KeyParams& params) { | 159 bool Cryptographer::AddKey(const KeyParams& params) { |
| 166 // Create the new Nigori and make it the default encryptor. | 160 // Create the new Nigori and make it the default encryptor. |
| 167 std::unique_ptr<Nigori> nigori(new Nigori); | 161 std::unique_ptr<Nigori> nigori(new Nigori); |
| 168 if (!nigori->InitByDerivation(params.hostname, | 162 if (!nigori->InitByDerivation(params.hostname, params.username, |
| 169 params.username, | |
| 170 params.password)) { | 163 params.password)) { |
| 171 NOTREACHED(); // Invalid username or password. | 164 NOTREACHED(); // Invalid username or password. |
| 172 return false; | 165 return false; |
| 173 } | 166 } |
| 174 return AddKeyImpl(std::move(nigori), true); | 167 return AddKeyImpl(std::move(nigori), true); |
| 175 } | 168 } |
| 176 | 169 |
| 177 bool Cryptographer::AddNonDefaultKey(const KeyParams& params) { | 170 bool Cryptographer::AddNonDefaultKey(const KeyParams& params) { |
| 178 DCHECK(is_initialized()); | 171 DCHECK(is_initialized()); |
| 179 // Create the new Nigori and add it to the keybag. | 172 // Create the new Nigori and add it to the keybag. |
| 180 std::unique_ptr<Nigori> nigori(new Nigori); | 173 std::unique_ptr<Nigori> nigori(new Nigori); |
| 181 if (!nigori->InitByDerivation(params.hostname, | 174 if (!nigori->InitByDerivation(params.hostname, params.username, |
| 182 params.username, | |
| 183 params.password)) { | 175 params.password)) { |
| 184 NOTREACHED(); // Invalid username or password. | 176 NOTREACHED(); // Invalid username or password. |
| 185 return false; | 177 return false; |
| 186 } | 178 } |
| 187 return AddKeyImpl(std::move(nigori), false); | 179 return AddKeyImpl(std::move(nigori), false); |
| 188 } | 180 } |
| 189 | 181 |
| 190 bool Cryptographer::AddKeyFromBootstrapToken( | 182 bool Cryptographer::AddKeyFromBootstrapToken( |
| 191 const std::string& restored_bootstrap_token) { | 183 const std::string& restored_bootstrap_token) { |
| 192 // Create the new Nigori and make it the default encryptor. | 184 // Create the new Nigori and make it the default encryptor. |
| 193 std::string serialized_nigori_key = UnpackBootstrapToken( | 185 std::string serialized_nigori_key = |
| 194 restored_bootstrap_token); | 186 UnpackBootstrapToken(restored_bootstrap_token); |
| 195 return ImportNigoriKey(serialized_nigori_key); | 187 return ImportNigoriKey(serialized_nigori_key); |
| 196 } | 188 } |
| 197 | 189 |
| 198 bool Cryptographer::AddKeyImpl(std::unique_ptr<Nigori> initialized_nigori, | 190 bool Cryptographer::AddKeyImpl(std::unique_ptr<Nigori> initialized_nigori, |
| 199 bool set_as_default) { | 191 bool set_as_default) { |
| 200 std::string name; | 192 std::string name; |
| 201 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { | 193 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { |
| 202 NOTREACHED(); | 194 NOTREACHED(); |
| 203 return false; | 195 return false; |
| 204 } | 196 } |
| 205 | 197 |
| 206 nigoris_[name] = make_linked_ptr(initialized_nigori.release()); | 198 nigoris_[name] = make_linked_ptr(initialized_nigori.release()); |
| 207 | 199 |
| 208 // Check if the key we just added can decrypt the pending keys and add them | 200 // Check if the key we just added can decrypt the pending keys and add them |
| 209 // too if so. | 201 // too if so. |
| 210 if (pending_keys_.get() && CanDecrypt(*pending_keys_)) { | 202 if (pending_keys_.get() && CanDecrypt(*pending_keys_)) { |
| 211 sync_pb::NigoriKeyBag pending_bag; | 203 sync_pb::NigoriKeyBag pending_bag; |
| 212 Decrypt(*pending_keys_, &pending_bag); | 204 Decrypt(*pending_keys_, &pending_bag); |
| 213 InstallKeyBag(pending_bag); | 205 InstallKeyBag(pending_bag); |
| 214 SetDefaultKey(pending_keys_->key_name()); | 206 SetDefaultKey(pending_keys_->key_name()); |
| 215 pending_keys_.reset(); | 207 pending_keys_.reset(); |
| 216 } | 208 } |
| 217 | 209 |
| 218 // The just-added key takes priority over the pending keys as default. | 210 // The just-added key takes priority over the pending keys as default. |
| 219 if (set_as_default) SetDefaultKey(name); | 211 if (set_as_default) |
| 212 SetDefaultKey(name); |
| 220 return true; | 213 return true; |
| 221 } | 214 } |
| 222 | 215 |
| 223 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { | 216 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { |
| 224 DCHECK(CanDecrypt(encrypted)); | 217 DCHECK(CanDecrypt(encrypted)); |
| 225 | 218 |
| 226 sync_pb::NigoriKeyBag bag; | 219 sync_pb::NigoriKeyBag bag; |
| 227 if (!Decrypt(encrypted, &bag)) | 220 if (!Decrypt(encrypted, &bag)) |
| 228 return; | 221 return; |
| 229 InstallKeyBag(bag); | 222 InstallKeyBag(bag); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 240 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); | 233 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); |
| 241 } | 234 } |
| 242 | 235 |
| 243 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { | 236 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { |
| 244 DCHECK(has_pending_keys()); | 237 DCHECK(has_pending_keys()); |
| 245 return *(pending_keys_.get()); | 238 return *(pending_keys_.get()); |
| 246 } | 239 } |
| 247 | 240 |
| 248 bool Cryptographer::DecryptPendingKeys(const KeyParams& params) { | 241 bool Cryptographer::DecryptPendingKeys(const KeyParams& params) { |
| 249 Nigori nigori; | 242 Nigori nigori; |
| 250 if (!nigori.InitByDerivation(params.hostname, | 243 if (!nigori.InitByDerivation(params.hostname, params.username, |
| 251 params.username, | |
| 252 params.password)) { | 244 params.password)) { |
| 253 NOTREACHED(); | 245 NOTREACHED(); |
| 254 return false; | 246 return false; |
| 255 } | 247 } |
| 256 | 248 |
| 257 std::string plaintext; | 249 std::string plaintext; |
| 258 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) | 250 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) |
| 259 return false; | 251 return false; |
| 260 | 252 |
| 261 sync_pb::NigoriKeyBag bag; | 253 sync_pb::NigoriKeyBag bag; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 return unencrypted_token; | 297 return unencrypted_token; |
| 306 } | 298 } |
| 307 | 299 |
| 308 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { | 300 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { |
| 309 int key_size = bag.key_size(); | 301 int key_size = bag.key_size(); |
| 310 for (int i = 0; i < key_size; ++i) { | 302 for (int i = 0; i < key_size; ++i) { |
| 311 const sync_pb::NigoriKey key = bag.key(i); | 303 const sync_pb::NigoriKey key = bag.key(i); |
| 312 // Only use this key if we don't already know about it. | 304 // Only use this key if we don't already know about it. |
| 313 if (nigoris_.end() == nigoris_.find(key.name())) { | 305 if (nigoris_.end() == nigoris_.find(key.name())) { |
| 314 std::unique_ptr<Nigori> new_nigori(new Nigori); | 306 std::unique_ptr<Nigori> new_nigori(new Nigori); |
| 315 if (!new_nigori->InitByImport(key.user_key(), | 307 if (!new_nigori->InitByImport(key.user_key(), key.encryption_key(), |
| 316 key.encryption_key(), | |
| 317 key.mac_key())) { | 308 key.mac_key())) { |
| 318 NOTREACHED(); | 309 NOTREACHED(); |
| 319 continue; | 310 continue; |
| 320 } | 311 } |
| 321 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); | 312 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); |
| 322 } | 313 } |
| 323 } | 314 } |
| 324 } | 315 } |
| 325 | 316 |
| 326 bool Cryptographer::KeybagIsStale( | 317 bool Cryptographer::KeybagIsStale( |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 NOTREACHED(); | 367 NOTREACHED(); |
| 377 return false; | 368 return false; |
| 378 } | 369 } |
| 379 | 370 |
| 380 if (!AddKeyImpl(std::move(nigori), true)) | 371 if (!AddKeyImpl(std::move(nigori), true)) |
| 381 return false; | 372 return false; |
| 382 return true; | 373 return true; |
| 383 } | 374 } |
| 384 | 375 |
| 385 } // namespace syncer | 376 } // namespace syncer |
| OLD | NEW |