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 |