Chromium Code Reviews| 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/logging.h" | 10 #include "base/logging.h" |
| 11 #include "sync/protocol/nigori_specifics.pb.h" | 11 #include "sync/protocol/nigori_specifics.pb.h" |
| 12 #include "sync/util/encryptor.h" | 12 #include "sync/util/encryptor.h" |
| 13 | 13 |
| 14 namespace syncer { | 14 namespace syncer { |
| 15 | 15 |
| 16 const char kNigoriTag[] = "google_chrome_nigori"; | 16 const char kNigoriTag[] = "google_chrome_nigori"; |
| 17 | 17 |
| 18 // We name a particular Nigori instance (ie. a triplet consisting of a hostname, | 18 // 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 | 19 // a username, and a password) by calling Permute on this string. Since the |
| 20 // output of Permute is always the same for a given triplet, clients will always | 20 // output of Permute is always the same for a given triplet, clients will always |
| 21 // assign the same name to a particular triplet. | 21 // assign the same name to a particular triplet. |
| 22 const char kNigoriKeyName[] = "nigori-key"; | 22 const char kNigoriKeyName[] = "nigori-key"; |
| 23 | 23 |
| 24 Cryptographer::Cryptographer(Encryptor* encryptor) | 24 Cryptographer::Cryptographer(Encryptor* encryptor) |
| 25 : encryptor_(encryptor), | 25 : encryptor_(encryptor) { |
| 26 default_nigori_(NULL), | |
| 27 keystore_nigori_(NULL) { | |
| 28 DCHECK(encryptor); | 26 DCHECK(encryptor); |
| 29 } | 27 } |
| 30 | 28 |
| 31 Cryptographer::~Cryptographer() {} | 29 Cryptographer::~Cryptographer() {} |
| 32 | 30 |
| 33 | 31 |
| 34 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { | 32 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) { |
| 35 if (is_initialized()) { | 33 if (is_initialized()) { |
| 36 NOTREACHED(); | 34 NOTREACHED(); |
| 37 return; | 35 return; |
| 38 } | 36 } |
| 39 | 37 |
| 40 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | 38 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); |
| 41 if (nigori.get()) | 39 if (nigori.get()) |
| 42 AddKeyImpl(nigori.release(), false); | 40 AddKeyImpl(nigori.Pass()); |
| 43 } | |
| 44 | |
| 45 void Cryptographer::BootstrapKeystoreKey( | |
| 46 const std::string& restored_bootstrap_token) { | |
| 47 if (keystore_nigori_) { | |
| 48 NOTREACHED(); | |
| 49 return; | |
| 50 } | |
| 51 | |
| 52 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | |
| 53 if (nigori.get()) | |
| 54 AddKeyImpl(nigori.release(), true); | |
| 55 } | 41 } |
| 56 | 42 |
| 57 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { | 43 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const { |
| 58 return nigoris_.end() != nigoris_.find(data.key_name()); | 44 return nigoris_.end() != nigoris_.find(data.key_name()); |
| 59 } | 45 } |
| 60 | 46 |
| 61 bool Cryptographer::CanDecryptUsingDefaultKey( | 47 bool Cryptographer::CanDecryptUsingDefaultKey( |
| 62 const sync_pb::EncryptedData& data) const { | 48 const sync_pb::EncryptedData& data) const { |
| 63 return default_nigori_ && (data.key_name() == default_nigori_->first); | 49 return default_nigori_.get() && (data.key_name() == default_nigori_name_); |
| 64 } | 50 } |
| 65 | 51 |
| 66 bool Cryptographer::Encrypt( | 52 bool Cryptographer::Encrypt( |
| 67 const ::google::protobuf::MessageLite& message, | 53 const ::google::protobuf::MessageLite& message, |
| 68 sync_pb::EncryptedData* encrypted) const { | 54 sync_pb::EncryptedData* encrypted) const { |
| 69 DCHECK(encrypted); | 55 DCHECK(encrypted); |
| 70 if (!default_nigori_) { | 56 if (!default_nigori_.get()) { |
| 71 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; | 57 LOG(ERROR) << "Cryptographer not ready, failed to encrypt."; |
| 72 return false; | 58 return false; |
| 73 } | 59 } |
| 60 DCHECK(nigoris_.find(default_nigori_name_) != nigoris_.end()); | |
|
akalin
2012/08/27 22:06:55
do we want to return false if either of these chec
Nicolas Zea
2012/08/28 01:18:50
Given that getting this wrong runs the risk of cor
| |
| 61 DCHECK_EQ(default_nigori_.get(), | |
| 62 nigoris_.find(default_nigori_name_)->second.get()); | |
| 74 | 63 |
| 75 std::string serialized; | 64 std::string serialized; |
| 76 if (!message.SerializeToString(&serialized)) { | 65 if (!message.SerializeToString(&serialized)) { |
| 77 LOG(ERROR) << "Message is invalid/missing a required field."; | 66 LOG(ERROR) << "Message is invalid/missing a required field."; |
| 78 return false; | 67 return false; |
| 79 } | 68 } |
| 80 | 69 |
| 81 if (CanDecryptUsingDefaultKey(*encrypted)) { | 70 if (CanDecryptUsingDefaultKey(*encrypted)) { |
| 82 const std::string& original_serialized = DecryptToString(*encrypted); | 71 const std::string& original_serialized = DecryptToString(*encrypted); |
| 83 if (original_serialized == serialized) { | 72 if (original_serialized == serialized) { |
| 84 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; | 73 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches."; |
| 85 return true; | 74 return true; |
| 86 } | 75 } |
| 87 } | 76 } |
| 88 | 77 |
| 89 encrypted->set_key_name(default_nigori_->first); | 78 encrypted->set_key_name(default_nigori_name_); |
| 90 if (!default_nigori_->second->Encrypt(serialized, | 79 if (!default_nigori_->Encrypt(serialized, |
| 91 encrypted->mutable_blob())) { | 80 encrypted->mutable_blob())) { |
| 92 LOG(ERROR) << "Failed to encrypt data."; | 81 LOG(ERROR) << "Failed to encrypt data."; |
| 93 return false; | 82 return false; |
| 94 } | 83 } |
| 95 return true; | 84 return true; |
| 96 } | 85 } |
| 97 | 86 |
| 98 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, | 87 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted, |
| 99 ::google::protobuf::MessageLite* message) const { | 88 ::google::protobuf::MessageLite* message) const { |
| 100 DCHECK(message); | 89 DCHECK(message); |
| 101 std::string plaintext = DecryptToString(encrypted); | 90 std::string plaintext = DecryptToString(encrypted); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 | 129 |
| 141 bool Cryptographer::AddKey(const KeyParams& params) { | 130 bool Cryptographer::AddKey(const KeyParams& params) { |
| 142 // Create the new Nigori and make it the default encryptor. | 131 // Create the new Nigori and make it the default encryptor. |
| 143 scoped_ptr<Nigori> nigori(new Nigori); | 132 scoped_ptr<Nigori> nigori(new Nigori); |
| 144 if (!nigori->InitByDerivation(params.hostname, | 133 if (!nigori->InitByDerivation(params.hostname, |
| 145 params.username, | 134 params.username, |
| 146 params.password)) { | 135 params.password)) { |
| 147 NOTREACHED(); // Invalid username or password. | 136 NOTREACHED(); // Invalid username or password. |
| 148 return false; | 137 return false; |
| 149 } | 138 } |
| 150 return AddKeyImpl(nigori.release(), false); | 139 return AddKeyImpl(nigori.Pass()); |
| 151 } | 140 } |
| 152 | 141 |
| 153 bool Cryptographer::AddKeyFromBootstrapToken( | 142 bool Cryptographer::AddKeyFromBootstrapToken( |
| 154 const std::string restored_bootstrap_token) { | 143 const std::string restored_bootstrap_token) { |
| 155 // Create the new Nigori and make it the default encryptor. | 144 // Create the new Nigori and make it the default encryptor. |
| 156 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); | 145 scoped_ptr<Nigori> nigori(UnpackBootstrapToken(restored_bootstrap_token)); |
| 157 if (!nigori.get()) | 146 if (!nigori.get()) |
| 158 return false; | 147 return false; |
| 159 return AddKeyImpl(nigori.release(), false); | 148 return AddKeyImpl(nigori.Pass()); |
| 160 } | 149 } |
| 161 | 150 |
| 162 bool Cryptographer::AddKeyImpl(Nigori* initialized_nigori, | 151 bool Cryptographer::AddKeyImpl(scoped_ptr<Nigori> initialized_nigori) { |
| 163 bool is_keystore_key) { | |
| 164 scoped_ptr<Nigori> nigori(initialized_nigori); | |
| 165 std::string name; | 152 std::string name; |
| 166 if (!nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { | 153 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) { |
| 167 NOTREACHED(); | 154 NOTREACHED(); |
| 168 return false; | 155 return false; |
| 169 } | 156 } |
| 170 nigoris_[name] = make_linked_ptr(nigori.release()); | 157 default_nigori_ = make_linked_ptr(initialized_nigori.release()); |
| 171 if (is_keystore_key) | 158 nigoris_[name] = default_nigori_; |
| 172 keystore_nigori_ = &*nigoris_.find(name); | 159 default_nigori_name_ = name; |
| 173 else | |
| 174 default_nigori_ = &*nigoris_.find(name); | |
| 175 return true; | 160 return true; |
| 176 } | 161 } |
| 177 | 162 |
| 178 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { | 163 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) { |
| 179 DCHECK(CanDecrypt(encrypted)); | 164 DCHECK(CanDecrypt(encrypted)); |
| 180 | 165 |
| 181 sync_pb::NigoriKeyBag bag; | 166 sync_pb::NigoriKeyBag bag; |
| 182 if (!Decrypt(encrypted, &bag)) | 167 if (!Decrypt(encrypted, &bag)) |
| 183 return; | 168 return; |
| 184 InstallKeyBag(bag); | 169 InstallKeyBag(bag); |
| 185 } | 170 } |
| 186 | 171 |
| 187 void Cryptographer::SetDefaultKey(const std::string& key_name) { | 172 void Cryptographer::SetDefaultKey(const std::string& key_name) { |
| 188 DCHECK(nigoris_.end() != nigoris_.find(key_name)); | 173 DCHECK(nigoris_.end() != nigoris_.find(key_name)); |
| 189 default_nigori_ = &*nigoris_.find(key_name); | 174 default_nigori_ = nigoris_.find(key_name)->second; |
|
akalin
2012/08/27 22:06:55
it seems like this'll crash (in release) if the DC
Nicolas Zea
2012/08/28 01:18:50
I think a crash would be appropriate here. If this
| |
| 175 default_nigori_name_ = key_name; | |
| 190 } | 176 } |
| 191 | 177 |
| 192 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { | 178 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) { |
| 193 DCHECK(!CanDecrypt(encrypted)); | 179 DCHECK(!CanDecrypt(encrypted)); |
| 194 DCHECK(!encrypted.blob().empty()); | 180 DCHECK(!encrypted.blob().empty()); |
| 195 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); | 181 pending_keys_.reset(new sync_pb::EncryptedData(encrypted)); |
| 196 } | 182 } |
| 197 | 183 |
| 198 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { | 184 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const { |
| 199 DCHECK(has_pending_keys()); | 185 DCHECK(has_pending_keys()); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 212 std::string plaintext; | 198 std::string plaintext; |
| 213 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) | 199 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext)) |
| 214 return false; | 200 return false; |
| 215 | 201 |
| 216 sync_pb::NigoriKeyBag bag; | 202 sync_pb::NigoriKeyBag bag; |
| 217 if (!bag.ParseFromString(plaintext)) { | 203 if (!bag.ParseFromString(plaintext)) { |
| 218 NOTREACHED(); | 204 NOTREACHED(); |
| 219 return false; | 205 return false; |
| 220 } | 206 } |
| 221 InstallKeyBag(bag); | 207 InstallKeyBag(bag); |
| 222 const std::string& new_default_key_name = pending_keys_->key_name(); | 208 const std::string& new_default_key_name = pending_keys_->key_name(); |
|
akalin
2012/08/27 22:06:55
can you use SetDefaultKey here?
Nicolas Zea
2012/08/28 01:18:50
Done.
| |
| 223 DCHECK(nigoris_.end() != nigoris_.find(new_default_key_name)); | 209 DCHECK(nigoris_.end() != nigoris_.find(new_default_key_name)); |
| 224 default_nigori_ = &*nigoris_.find(new_default_key_name); | 210 default_nigori_ = nigoris_.find(new_default_key_name)->second; |
| 211 default_nigori_name_ = new_default_key_name; | |
| 225 pending_keys_.reset(); | 212 pending_keys_.reset(); |
| 226 return true; | 213 return true; |
| 227 } | 214 } |
| 228 | 215 |
| 229 bool Cryptographer::GetBootstrapToken(std::string* token) const { | 216 bool Cryptographer::GetBootstrapToken(std::string* token) const { |
| 230 DCHECK(token); | 217 DCHECK(token); |
| 231 if (!is_initialized()) | 218 if (!is_initialized()) |
| 232 return false; | 219 return false; |
| 233 | 220 |
| 234 return PackBootstrapToken(default_nigori_->second.get(), token); | 221 return PackBootstrapToken(default_nigori_.get(), token); |
| 235 } | |
| 236 | |
| 237 bool Cryptographer::GetKeystoreKeyBootstrapToken( | |
| 238 std::string* token) const { | |
| 239 DCHECK(token); | |
| 240 if (!HasKeystoreKey()) | |
| 241 return false; | |
| 242 | |
| 243 return PackBootstrapToken(keystore_nigori_->second.get(), token); | |
| 244 } | 222 } |
| 245 | 223 |
| 246 bool Cryptographer::PackBootstrapToken(const Nigori* nigori, | 224 bool Cryptographer::PackBootstrapToken(const Nigori* nigori, |
| 247 std::string* pack_into) const { | 225 std::string* pack_into) const { |
| 248 DCHECK(pack_into); | 226 DCHECK(pack_into); |
| 249 DCHECK(nigori); | 227 DCHECK(nigori); |
| 250 | 228 |
| 251 sync_pb::NigoriKey key; | 229 sync_pb::NigoriKey key; |
| 252 if (!nigori->ExportKeys(key.mutable_user_key(), | 230 if (!nigori->ExportKeys(key.mutable_user_key(), |
| 253 key.mutable_encryption_key(), | 231 key.mutable_encryption_key(), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 scoped_ptr<Nigori> nigori(new Nigori); | 278 scoped_ptr<Nigori> nigori(new Nigori); |
| 301 if (!nigori->InitByImport(key.user_key(), key.encryption_key(), | 279 if (!nigori->InitByImport(key.user_key(), key.encryption_key(), |
| 302 key.mac_key())) { | 280 key.mac_key())) { |
| 303 NOTREACHED(); | 281 NOTREACHED(); |
| 304 return NULL; | 282 return NULL; |
| 305 } | 283 } |
| 306 | 284 |
| 307 return nigori.release(); | 285 return nigori.release(); |
| 308 } | 286 } |
| 309 | 287 |
| 310 bool Cryptographer::SetKeystoreKey(const std::string& keystore_key) { | |
| 311 if (keystore_key.empty()) | |
| 312 return false; | |
| 313 KeyParams params = {"localhost", "dummy", keystore_key}; | |
| 314 | |
| 315 // Create the new Nigori and make it the default keystore encryptor. | |
| 316 scoped_ptr<Nigori> nigori(new Nigori); | |
| 317 if (!nigori->InitByDerivation(params.hostname, | |
| 318 params.username, | |
| 319 params.password)) { | |
| 320 NOTREACHED(); // Invalid username or password. | |
| 321 return false; | |
| 322 } | |
| 323 | |
| 324 return AddKeyImpl(nigori.release(), true); | |
| 325 } | |
| 326 | |
| 327 bool Cryptographer::HasKeystoreKey() const { | |
| 328 return keystore_nigori_ != NULL; | |
| 329 } | |
| 330 | |
| 331 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { | 288 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) { |
| 332 int key_size = bag.key_size(); | 289 int key_size = bag.key_size(); |
| 333 for (int i = 0; i < key_size; ++i) { | 290 for (int i = 0; i < key_size; ++i) { |
| 334 const sync_pb::NigoriKey key = bag.key(i); | 291 const sync_pb::NigoriKey key = bag.key(i); |
| 335 // Only use this key if we don't already know about it. | 292 // Only use this key if we don't already know about it. |
| 336 if (nigoris_.end() == nigoris_.find(key.name())) { | 293 if (nigoris_.end() == nigoris_.find(key.name())) { |
| 337 scoped_ptr<Nigori> new_nigori(new Nigori); | 294 scoped_ptr<Nigori> new_nigori(new Nigori); |
| 338 if (!new_nigori->InitByImport(key.user_key(), | 295 if (!new_nigori->InitByImport(key.user_key(), |
| 339 key.encryption_key(), | 296 key.encryption_key(), |
| 340 key.mac_key())) { | 297 key.mac_key())) { |
| 341 NOTREACHED(); | 298 NOTREACHED(); |
| 342 continue; | 299 continue; |
| 343 } | 300 } |
| 344 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); | 301 nigoris_[key.name()] = make_linked_ptr(new_nigori.release()); |
| 345 } | 302 } |
| 346 } | 303 } |
| 347 } | 304 } |
| 348 | 305 |
| 349 } // namespace syncer | 306 } // namespace syncer |
| OLD | NEW |