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

Side by Side Diff: sync/util/cryptographer.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months 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
« no previous file with comments | « sync/util/cryptographer.h ('k') | sync/util/cryptographer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "sync/util/cryptographer.h"
6
7 #include <stddef.h>
8 #include <algorithm>
9 #include <utility>
10
11 #include "base/base64.h"
12 #include "base/logging.h"
13 #include "sync/protocol/nigori_specifics.pb.h"
14 #include "sync/util/encryptor.h"
15
16 namespace syncer {
17
18 const char kNigoriTag[] = "google_chrome_nigori";
19
20 // 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 // output of Permute is always the same for a given triplet, clients will always
23 // assign the same name to a particular triplet.
24 const char kNigoriKeyName[] = "nigori-key";
25
26 Cryptographer::Cryptographer(Encryptor* encryptor)
27 : encryptor_(encryptor) {
28 DCHECK(encryptor);
29 }
30
31 Cryptographer::Cryptographer(const Cryptographer& other)
32 : encryptor_(other.encryptor_),
33 default_nigori_name_(other.default_nigori_name_) {
34 for (NigoriMap::const_iterator it = other.nigoris_.begin();
35 it != other.nigoris_.end();
36 ++it) {
37 std::string user_key, encryption_key, mac_key;
38 it->second->ExportKeys(&user_key, &encryption_key, &mac_key);
39 linked_ptr<Nigori> nigori_copy(new Nigori());
40 nigori_copy->InitByImport(user_key, encryption_key, mac_key);
41 nigoris_.insert(std::make_pair(it->first, nigori_copy));
42 }
43
44 if (other.pending_keys_) {
45 pending_keys_.reset(new sync_pb::EncryptedData(*(other.pending_keys_)));
46 }
47 }
48
49 Cryptographer::~Cryptographer() {}
50
51
52 void Cryptographer::Bootstrap(const std::string& restored_bootstrap_token) {
53 if (is_initialized()) {
54 NOTREACHED();
55 return;
56 }
57
58 std::string serialized_nigori_key =
59 UnpackBootstrapToken(restored_bootstrap_token);
60 if (serialized_nigori_key.empty())
61 return;
62 ImportNigoriKey(serialized_nigori_key);
63 }
64
65 bool Cryptographer::CanDecrypt(const sync_pb::EncryptedData& data) const {
66 return nigoris_.end() != nigoris_.find(data.key_name());
67 }
68
69 bool Cryptographer::CanDecryptUsingDefaultKey(
70 const sync_pb::EncryptedData& data) const {
71 return !default_nigori_name_.empty() &&
72 data.key_name() == default_nigori_name_;
73 }
74
75 bool Cryptographer::Encrypt(
76 const ::google::protobuf::MessageLite& message,
77 sync_pb::EncryptedData* encrypted) const {
78 DCHECK(encrypted);
79 if (default_nigori_name_.empty()) {
80 LOG(ERROR) << "Cryptographer not ready, failed to encrypt.";
81 return false;
82 }
83
84 std::string serialized;
85 if (!message.SerializeToString(&serialized)) {
86 LOG(ERROR) << "Message is invalid/missing a required field.";
87 return false;
88 }
89
90 return EncryptString(serialized, encrypted);
91 }
92
93 bool Cryptographer::EncryptString(
94 const std::string& serialized,
95 sync_pb::EncryptedData* encrypted) const {
96 if (CanDecryptUsingDefaultKey(*encrypted)) {
97 const std::string& original_serialized = DecryptToString(*encrypted);
98 if (original_serialized == serialized) {
99 DVLOG(2) << "Re-encryption unnecessary, encrypted data already matches.";
100 return true;
101 }
102 }
103
104 NigoriMap::const_iterator default_nigori =
105 nigoris_.find(default_nigori_name_);
106 if (default_nigori == nigoris_.end()) {
107 LOG(ERROR) << "Corrupt default key.";
108 return false;
109 }
110
111 encrypted->set_key_name(default_nigori_name_);
112 if (!default_nigori->second->Encrypt(serialized,
113 encrypted->mutable_blob())) {
114 LOG(ERROR) << "Failed to encrypt data.";
115 return false;
116 }
117 return true;
118 }
119
120 bool Cryptographer::Decrypt(const sync_pb::EncryptedData& encrypted,
121 ::google::protobuf::MessageLite* message) const {
122 DCHECK(message);
123 std::string plaintext = DecryptToString(encrypted);
124 return message->ParseFromString(plaintext);
125 }
126
127 std::string Cryptographer::DecryptToString(
128 const sync_pb::EncryptedData& encrypted) const {
129 NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name());
130 if (nigoris_.end() == it) {
131 // The key used to encrypt the blob is not part of the set of installed
132 // nigoris.
133 LOG(ERROR) << "Cannot decrypt message";
134 return std::string();
135 }
136
137 std::string plaintext;
138 if (!it->second->Decrypt(encrypted.blob(), &plaintext)) {
139 return std::string();
140 }
141
142 return plaintext;
143 }
144
145 bool Cryptographer::GetKeys(sync_pb::EncryptedData* encrypted) const {
146 DCHECK(encrypted);
147 DCHECK(!nigoris_.empty());
148
149 // Create a bag of all the Nigori parameters we know about.
150 sync_pb::NigoriKeyBag bag;
151 for (NigoriMap::const_iterator it = nigoris_.begin(); it != nigoris_.end();
152 ++it) {
153 const Nigori& nigori = *it->second;
154 sync_pb::NigoriKey* key = bag.add_key();
155 key->set_name(it->first);
156 nigori.ExportKeys(key->mutable_user_key(),
157 key->mutable_encryption_key(),
158 key->mutable_mac_key());
159 }
160
161 // Encrypt the bag with the default Nigori.
162 return Encrypt(bag, encrypted);
163 }
164
165 bool Cryptographer::AddKey(const KeyParams& params) {
166 // Create the new Nigori and make it the default encryptor.
167 std::unique_ptr<Nigori> nigori(new Nigori);
168 if (!nigori->InitByDerivation(params.hostname,
169 params.username,
170 params.password)) {
171 NOTREACHED(); // Invalid username or password.
172 return false;
173 }
174 return AddKeyImpl(std::move(nigori), true);
175 }
176
177 bool Cryptographer::AddNonDefaultKey(const KeyParams& params) {
178 DCHECK(is_initialized());
179 // Create the new Nigori and add it to the keybag.
180 std::unique_ptr<Nigori> nigori(new Nigori);
181 if (!nigori->InitByDerivation(params.hostname,
182 params.username,
183 params.password)) {
184 NOTREACHED(); // Invalid username or password.
185 return false;
186 }
187 return AddKeyImpl(std::move(nigori), false);
188 }
189
190 bool Cryptographer::AddKeyFromBootstrapToken(
191 const std::string& restored_bootstrap_token) {
192 // Create the new Nigori and make it the default encryptor.
193 std::string serialized_nigori_key = UnpackBootstrapToken(
194 restored_bootstrap_token);
195 return ImportNigoriKey(serialized_nigori_key);
196 }
197
198 bool Cryptographer::AddKeyImpl(std::unique_ptr<Nigori> initialized_nigori,
199 bool set_as_default) {
200 std::string name;
201 if (!initialized_nigori->Permute(Nigori::Password, kNigoriKeyName, &name)) {
202 NOTREACHED();
203 return false;
204 }
205
206 nigoris_[name] = make_linked_ptr(initialized_nigori.release());
207
208 // Check if the key we just added can decrypt the pending keys and add them
209 // too if so.
210 if (pending_keys_.get() && CanDecrypt(*pending_keys_)) {
211 sync_pb::NigoriKeyBag pending_bag;
212 Decrypt(*pending_keys_, &pending_bag);
213 InstallKeyBag(pending_bag);
214 SetDefaultKey(pending_keys_->key_name());
215 pending_keys_.reset();
216 }
217
218 // The just-added key takes priority over the pending keys as default.
219 if (set_as_default) SetDefaultKey(name);
220 return true;
221 }
222
223 void Cryptographer::InstallKeys(const sync_pb::EncryptedData& encrypted) {
224 DCHECK(CanDecrypt(encrypted));
225
226 sync_pb::NigoriKeyBag bag;
227 if (!Decrypt(encrypted, &bag))
228 return;
229 InstallKeyBag(bag);
230 }
231
232 void Cryptographer::SetDefaultKey(const std::string& key_name) {
233 DCHECK(nigoris_.end() != nigoris_.find(key_name));
234 default_nigori_name_ = key_name;
235 }
236
237 void Cryptographer::SetPendingKeys(const sync_pb::EncryptedData& encrypted) {
238 DCHECK(!CanDecrypt(encrypted));
239 DCHECK(!encrypted.blob().empty());
240 pending_keys_.reset(new sync_pb::EncryptedData(encrypted));
241 }
242
243 const sync_pb::EncryptedData& Cryptographer::GetPendingKeys() const {
244 DCHECK(has_pending_keys());
245 return *(pending_keys_.get());
246 }
247
248 bool Cryptographer::DecryptPendingKeys(const KeyParams& params) {
249 Nigori nigori;
250 if (!nigori.InitByDerivation(params.hostname,
251 params.username,
252 params.password)) {
253 NOTREACHED();
254 return false;
255 }
256
257 std::string plaintext;
258 if (!nigori.Decrypt(pending_keys_->blob(), &plaintext))
259 return false;
260
261 sync_pb::NigoriKeyBag bag;
262 if (!bag.ParseFromString(plaintext)) {
263 NOTREACHED();
264 return false;
265 }
266 InstallKeyBag(bag);
267 const std::string& new_default_key_name = pending_keys_->key_name();
268 SetDefaultKey(new_default_key_name);
269 pending_keys_.reset();
270 return true;
271 }
272
273 bool Cryptographer::GetBootstrapToken(std::string* token) const {
274 DCHECK(token);
275 std::string unencrypted_token = GetDefaultNigoriKeyData();
276 if (unencrypted_token.empty())
277 return false;
278
279 std::string encrypted_token;
280 if (!encryptor_->EncryptString(unencrypted_token, &encrypted_token)) {
281 return false;
282 }
283
284 base::Base64Encode(encrypted_token, token);
285
286 return true;
287 }
288
289 std::string Cryptographer::UnpackBootstrapToken(
290 const std::string& token) const {
291 if (token.empty())
292 return std::string();
293
294 std::string encrypted_data;
295 if (!base::Base64Decode(token, &encrypted_data)) {
296 DLOG(WARNING) << "Could not decode token.";
297 return std::string();
298 }
299
300 std::string unencrypted_token;
301 if (!encryptor_->DecryptString(encrypted_data, &unencrypted_token)) {
302 DLOG(WARNING) << "Decryption of bootstrap token failed.";
303 return std::string();
304 }
305 return unencrypted_token;
306 }
307
308 void Cryptographer::InstallKeyBag(const sync_pb::NigoriKeyBag& bag) {
309 int key_size = bag.key_size();
310 for (int i = 0; i < key_size; ++i) {
311 const sync_pb::NigoriKey key = bag.key(i);
312 // Only use this key if we don't already know about it.
313 if (nigoris_.end() == nigoris_.find(key.name())) {
314 std::unique_ptr<Nigori> new_nigori(new Nigori);
315 if (!new_nigori->InitByImport(key.user_key(),
316 key.encryption_key(),
317 key.mac_key())) {
318 NOTREACHED();
319 continue;
320 }
321 nigoris_[key.name()] = make_linked_ptr(new_nigori.release());
322 }
323 }
324 }
325
326 bool Cryptographer::KeybagIsStale(
327 const sync_pb::EncryptedData& encrypted_bag) const {
328 if (!is_ready())
329 return false;
330 if (encrypted_bag.blob().empty())
331 return true;
332 if (!CanDecrypt(encrypted_bag))
333 return false;
334 if (!CanDecryptUsingDefaultKey(encrypted_bag))
335 return true;
336 sync_pb::NigoriKeyBag bag;
337 if (!Decrypt(encrypted_bag, &bag)) {
338 LOG(ERROR) << "Failed to decrypt keybag for stale check. "
339 << "Assuming keybag is corrupted.";
340 return true;
341 }
342 if (static_cast<size_t>(bag.key_size()) < nigoris_.size())
343 return true;
344 return false;
345 }
346
347 std::string Cryptographer::GetDefaultNigoriKeyName() const {
348 return default_nigori_name_;
349 }
350
351 std::string Cryptographer::GetDefaultNigoriKeyData() const {
352 if (!is_initialized())
353 return std::string();
354 NigoriMap::const_iterator iter = nigoris_.find(default_nigori_name_);
355 if (iter == nigoris_.end())
356 return std::string();
357 sync_pb::NigoriKey key;
358 if (!iter->second->ExportKeys(key.mutable_user_key(),
359 key.mutable_encryption_key(),
360 key.mutable_mac_key()))
361 return std::string();
362 return key.SerializeAsString();
363 }
364
365 bool Cryptographer::ImportNigoriKey(const std::string& serialized_nigori_key) {
366 if (serialized_nigori_key.empty())
367 return false;
368
369 sync_pb::NigoriKey key;
370 if (!key.ParseFromString(serialized_nigori_key))
371 return false;
372
373 std::unique_ptr<Nigori> nigori(new Nigori);
374 if (!nigori->InitByImport(key.user_key(), key.encryption_key(),
375 key.mac_key())) {
376 NOTREACHED();
377 return false;
378 }
379
380 if (!AddKeyImpl(std::move(nigori), true))
381 return false;
382 return true;
383 }
384
385 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/util/cryptographer.h ('k') | sync/util/cryptographer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698