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