1 // Copyright 2019 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 "components/sync/nigori/pending_local_nigori_commit.h"
6
7 #include "base/feature_list.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/time/time.h"
10 #include "components/sync/base/sync_base_switches.h"
11 #include "components/sync/engine/sync_engine_switches.h"
12 #include "components/sync/nigori/cryptographer_impl.h"
13 #include "components/sync/nigori/keystore_keys_cryptographer.h"
14 #include "components/sync/nigori/nigori_state.h"
15
16 namespace syncer {
17
18 namespace {
19
20 using sync_pb::NigoriSpecifics;
21
22 // Returns the key derivation method to be used when a user sets a new
23 // custom passphrase.
GetDefaultKeyDerivationMethodForCustomPassphrase()24 KeyDerivationMethod GetDefaultKeyDerivationMethodForCustomPassphrase() {
25 if (base::FeatureList::IsEnabled(
26 switches::kSyncUseScryptForNewCustomPassphrases) &&
27 !base::FeatureList::IsEnabled(
28 switches::kSyncForceDisableScryptForCustomPassphrase)) {
29 return KeyDerivationMethod::SCRYPT_8192_8_11;
30 }
31
32 return KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003;
33 }
34
35 class CustomPassphraseSetter : public PendingLocalNigoriCommit {
36 public:
CustomPassphraseSetter(const std::string & passphrase,const base::RepeatingCallback<std::string ()> & random_salt_generator)37 CustomPassphraseSetter(
38 const std::string& passphrase,
39 const base::RepeatingCallback<std::string()>& random_salt_generator)
40 : passphrase_(passphrase),
41 key_derivation_params_(CreateKeyDerivationParamsForCustomPassphrase(
42 random_salt_generator)) {}
43
44 ~CustomPassphraseSetter() override = default;
45
TryApply(NigoriState * state) const46 bool TryApply(NigoriState* state) const override {
47 if (state->pending_keys.has_value()) {
48 return false;
49 }
50
51 switch (state->passphrase_type) {
52 case NigoriSpecifics::UNKNOWN:
53 return false;
54 case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
55 case NigoriSpecifics::CUSTOM_PASSPHRASE:
56 // Attempt to set the explicit passphrase when one was already set. It's
57 // possible if we received new NigoriSpecifics during the passphrase
58 // setup.
59 DVLOG(1)
60 << "Attempt to set explicit passphrase failed, because one was "
61 "already set.";
62 return false;
63 case NigoriSpecifics::IMPLICIT_PASSPHRASE:
64 case NigoriSpecifics::KEYSTORE_PASSPHRASE:
65 case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
66 break;
67 }
68
69 const std::string default_key_name =
70 state->cryptographer->EmplaceKey(passphrase_, key_derivation_params_);
71 if (default_key_name.empty()) {
72 DLOG(ERROR) << "Failed to set encryption passphrase";
73 return false;
74 }
75
76 state->cryptographer->SelectDefaultEncryptionKey(default_key_name);
77 state->pending_keystore_decryptor_token.reset();
78 state->passphrase_type = NigoriSpecifics::CUSTOM_PASSPHRASE;
79 state->custom_passphrase_key_derivation_params = key_derivation_params_;
80 state->encrypt_everything = true;
81 state->custom_passphrase_time = base::Time::Now();
82
83 return true;
84 }
85
OnSuccess(const NigoriState & state,SyncEncryptionHandler::Observer * observer)86 void OnSuccess(const NigoriState& state,
87 SyncEncryptionHandler::Observer* observer) override {
88 DCHECK(!state.pending_keys.has_value());
89
90 observer->OnPassphraseTypeChanged(PassphraseType::kCustomPassphrase,
91 state.custom_passphrase_time);
92 observer->OnCryptographerStateChanged(state.cryptographer.get(),
93 /*has_pending_keys=*/false);
94 observer->OnEncryptedTypesChanged(EncryptableUserTypes(),
95 /*encrypt_everything=*/true);
96 observer->OnPassphraseAccepted();
97
98 UMA_HISTOGRAM_BOOLEAN("Sync.CustomEncryption", true);
99 }
100
OnFailure(SyncEncryptionHandler::Observer * observer)101 void OnFailure(SyncEncryptionHandler::Observer* observer) override {
102 // TODO(crbug.com/922900): investigate whether we need to call
103 // OnPassphraseRequired() to prompt for decryption passphrase.
104 }
105
106 private:
107 const std::string passphrase_;
108 const KeyDerivationParams key_derivation_params_;
109
110 DISALLOW_COPY_AND_ASSIGN(CustomPassphraseSetter);
111 };
112
113 class KeystoreInitializer : public PendingLocalNigoriCommit {
114 public:
115 KeystoreInitializer() = default;
116 ~KeystoreInitializer() override = default;
117
TryApply(NigoriState * state) const118 bool TryApply(NigoriState* state) const override {
119 DCHECK(!state->keystore_keys_cryptographer->IsEmpty());
120 if (state->passphrase_type != NigoriSpecifics::UNKNOWN) {
121 return false;
122 }
123
124 state->passphrase_type = NigoriSpecifics::KEYSTORE_PASSPHRASE;
125 state->keystore_migration_time = base::Time::Now();
126 state->cryptographer =
127 state->keystore_keys_cryptographer->ToCryptographerImpl();
128 return true;
129 }
130
OnSuccess(const NigoriState & state,SyncEncryptionHandler::Observer * observer)131 void OnSuccess(const NigoriState& state,
132 SyncEncryptionHandler::Observer* observer) override {
133 // Note: |passphrase_time| isn't populated for keystore passphrase.
134 observer->OnPassphraseTypeChanged(PassphraseType::kKeystorePassphrase,
135 /*passphrase_time=*/base::Time());
136 observer->OnCryptographerStateChanged(state.cryptographer.get(),
137 /*has_pending_keys=*/false);
138 }
139
OnFailure(SyncEncryptionHandler::Observer * observer)140 void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
141
142 private:
143 DISALLOW_COPY_AND_ASSIGN(KeystoreInitializer);
144 };
145
146 class KeystoreReencryptor : public PendingLocalNigoriCommit {
147 public:
148 KeystoreReencryptor() = default;
149 ~KeystoreReencryptor() override = default;
150
TryApply(NigoriState * state) const151 bool TryApply(NigoriState* state) const override {
152 if (!state->NeedsKeystoreReencryption()) {
153 return false;
154 }
155 // TODO(crbug.com/922900): ensure that |cryptographer| contains all
156 // keystore keys? (In theory it's safe to add only last one).
157 const std::string new_default_key_name = state->cryptographer->EmplaceKey(
158 state->keystore_keys_cryptographer->keystore_keys().back(),
159 KeyDerivationParams::CreateForPbkdf2());
160 state->cryptographer->SelectDefaultEncryptionKey(new_default_key_name);
161 return true;
162 }
163
OnSuccess(const NigoriState & state,SyncEncryptionHandler::Observer * observer)164 void OnSuccess(const NigoriState& state,
165 SyncEncryptionHandler::Observer* observer) override {
166 observer->OnCryptographerStateChanged(state.cryptographer.get(),
167 /*has_pending_keys=*/false);
168 }
169
OnFailure(SyncEncryptionHandler::Observer * observer)170 void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
171
172 private:
173 DISALLOW_COPY_AND_ASSIGN(KeystoreReencryptor);
174 };
175
176 } // namespace
177
CreateKeyDerivationParamsForCustomPassphrase(const base::RepeatingCallback<std::string ()> & random_salt_generator)178 KeyDerivationParams CreateKeyDerivationParamsForCustomPassphrase(
179 const base::RepeatingCallback<std::string()>& random_salt_generator) {
180 KeyDerivationMethod method =
181 GetDefaultKeyDerivationMethodForCustomPassphrase();
182 switch (method) {
183 case KeyDerivationMethod::PBKDF2_HMAC_SHA1_1003:
184 return KeyDerivationParams::CreateForPbkdf2();
185 case KeyDerivationMethod::SCRYPT_8192_8_11:
186 return KeyDerivationParams::CreateForScrypt(random_salt_generator.Run());
187 case KeyDerivationMethod::UNSUPPORTED:
188 break;
189 }
190
191 NOTREACHED();
192 return KeyDerivationParams::CreateWithUnsupportedMethod();
193 }
194
195 // static
196 std::unique_ptr<PendingLocalNigoriCommit>
ForSetCustomPassphrase(const std::string & passphrase,const base::RepeatingCallback<std::string ()> & random_salt_generator)197 PendingLocalNigoriCommit::ForSetCustomPassphrase(
198 const std::string& passphrase,
199 const base::RepeatingCallback<std::string()>& random_salt_generator) {
200 return std::make_unique<CustomPassphraseSetter>(passphrase,
201 random_salt_generator);
202 }
203
204 // static
205 std::unique_ptr<PendingLocalNigoriCommit>
ForKeystoreInitialization()206 PendingLocalNigoriCommit::ForKeystoreInitialization() {
207 return std::make_unique<KeystoreInitializer>();
208 }
209
210 // static
211 std::unique_ptr<PendingLocalNigoriCommit>
ForKeystoreReencryption()212 PendingLocalNigoriCommit::ForKeystoreReencryption() {
213 return std::make_unique<KeystoreReencryptor>();
214 }
215
216 } // namespace syncer
217