Commit 5f3f808e authored by Mikel Astiz's avatar Mikel Astiz Committed by Commit Bot

Adopt base64-encoding prior to vault Nigori key derivation

Similarly to how it's done for keystore keys, the patch now adopts a
base64-encoding of the encryption keys, prior to the Nigori key
derivation (PBKDF2).

The main motivation is that the underlying crypto libraries don't
deal well with non-utf8 passphrases/passwords, or they diverge across
implementations (Java vs C++).

The rest of the code, prior to key derivation, continues to use binary
keys.

Bug: 1000146
Change-Id: Icaa88f285938f09e5fb8b72c9e11b8f90ab41840
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1950536
Commit-Queue: Mikel Astiz <mastiz@chromium.org>
Reviewed-by: default avatarMaksim Moskvitin <mmoskvitin@google.com>
Cr-Commit-Position: refs/heads/master@{#721532}
parent 73d0bacb
...@@ -89,8 +89,6 @@ GURL GetTrustedVaultRetrievalURL( ...@@ -89,8 +89,6 @@ GURL GetTrustedVaultRetrievalURL(
} }
KeyParams KeystoreKeyParams(const std::string& key) { KeyParams KeystoreKeyParams(const std::string& key) {
// Due to mis-encode of keystore keys to base64 we have to always encode such
// keys to provide backward compatibility.
std::string encoded_key; std::string encoded_key;
base::Base64Encode(key, &encoded_key); base::Base64Encode(key, &encoded_key);
return {syncer::KeyDerivationParams::CreateForPbkdf2(), return {syncer::KeyDerivationParams::CreateForPbkdf2(),
...@@ -159,8 +157,11 @@ sync_pb::NigoriSpecifics BuildTrustedVaultNigoriSpecifics( ...@@ -159,8 +157,11 @@ sync_pb::NigoriSpecifics BuildTrustedVaultNigoriSpecifics(
std::unique_ptr<syncer::CryptographerImpl> cryptographer = std::unique_ptr<syncer::CryptographerImpl> cryptographer =
syncer::CryptographerImpl::CreateEmpty(); syncer::CryptographerImpl::CreateEmpty();
for (const std::string& trusted_vault_key : trusted_vault_keys) { for (const std::string& trusted_vault_key : trusted_vault_keys) {
std::string encoded_key;
base::Base64Encode(trusted_vault_key, &encoded_key);
const std::string key_name = cryptographer->EmplaceKey( const std::string key_name = cryptographer->EmplaceKey(
trusted_vault_key, syncer::KeyDerivationParams::CreateForPbkdf2()); encoded_key, syncer::KeyDerivationParams::CreateForPbkdf2());
cryptographer->SelectDefaultEncryptionKey(key_name); cryptographer->SelectDefaultEncryptionKey(key_name);
} }
......
...@@ -43,8 +43,6 @@ const syncer::SyncFirstSetupCompleteSource kSetSourceFromTest = ...@@ -43,8 +43,6 @@ const syncer::SyncFirstSetupCompleteSource kSetSourceFromTest =
syncer::SyncFirstSetupCompleteSource::BASIC_FLOW; syncer::SyncFirstSetupCompleteSource::BASIC_FLOW;
syncer::KeyParams KeystoreKeyParams(const std::string& key) { syncer::KeyParams KeystoreKeyParams(const std::string& key) {
// Due to mis-encode of keystore keys to base64 we have to always encode such
// keys to provide backward compatibility.
std::string encoded_key; std::string encoded_key;
base::Base64Encode(key, &encoded_key); base::Base64Encode(key, &encoded_key);
return {syncer::KeyDerivationParams::CreateForPbkdf2(), return {syncer::KeyDerivationParams::CreateForPbkdf2(),
......
...@@ -93,6 +93,20 @@ KeyDerivationParams GetKeyDerivationParamsFromSpecifics( ...@@ -93,6 +93,20 @@ KeyDerivationParams GetKeyDerivationParamsFromSpecifics(
return KeyDerivationParams::CreateWithUnsupportedMethod(); return KeyDerivationParams::CreateWithUnsupportedMethod();
} }
// We need to apply base64 encoding before deriving Nigori keys because the
// underlying crypto libraries (in particular the Java counterparts in JDK's
// implementation for PBKDF2) assume the keys are utf8.
std::vector<std::string> Base64EncodeKeys(
const std::vector<std::string>& keys) {
std::vector<std::string> encoded_keystore_keys;
for (const std::string& key : keys) {
std::string encoded_key;
base::Base64Encode(key, &encoded_key);
encoded_keystore_keys.push_back(std::move(encoded_key));
}
return encoded_keystore_keys;
}
bool SpecificsHasValidKeyDerivationParams(const NigoriSpecifics& specifics) { bool SpecificsHasValidKeyDerivationParams(const NigoriSpecifics& specifics) {
switch (GetKeyDerivationMethodFromSpecifics(specifics)) { switch (GetKeyDerivationMethodFromSpecifics(specifics)) {
case KeyDerivationMethod::UNSUPPORTED: case KeyDerivationMethod::UNSUPPORTED:
...@@ -578,12 +592,11 @@ void NigoriSyncBridgeImpl::AddTrustedVaultDecryptionKeys( ...@@ -578,12 +592,11 @@ void NigoriSyncBridgeImpl::AddTrustedVaultDecryptionKeys(
return; return;
} }
const std::vector<std::string> encoded_keys = Base64EncodeKeys(keys);
NigoriKeyBag tmp_key_bag = NigoriKeyBag::CreateEmpty(); NigoriKeyBag tmp_key_bag = NigoriKeyBag::CreateEmpty();
for (const std::string& key : keys) { for (const std::string& encoded_key : encoded_keys) {
if (!key.empty()) { tmp_key_bag.AddKey(Nigori::CreateByDerivation(
tmp_key_bag.AddKey(Nigori::CreateByDerivation( GetKeyDerivationParamsForPendingKeys(), encoded_key));
GetKeyDerivationParamsForPendingKeys(), key));
}
} }
base::Optional<ModelError> error = TryDecryptPendingKeysWith(tmp_key_bag); base::Optional<ModelError> error = TryDecryptPendingKeysWith(tmp_key_bag);
...@@ -652,17 +665,8 @@ bool NigoriSyncBridgeImpl::SetKeystoreKeys( ...@@ -652,17 +665,8 @@ bool NigoriSyncBridgeImpl::SetKeystoreKeys(
return false; return false;
} }
std::vector<std::string> encoded_keystore_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
// We need to apply base64 encoding before using the keys to provide
// backward compatibility with non-USS implementation. It's actually needed
// only for the keys persisting, but was applied before passing keys to
// cryptographer, so we have to do the same.
base::Base64Encode(keys[i], &encoded_keystore_keys[i]);
}
state_.keystore_keys_cryptographer = state_.keystore_keys_cryptographer =
KeystoreKeysCryptographer::FromKeystoreKeys(encoded_keystore_keys); KeystoreKeysCryptographer::FromKeystoreKeys(Base64EncodeKeys(keys));
if (!state_.keystore_keys_cryptographer) { if (!state_.keystore_keys_cryptographer) {
state_.keystore_keys_cryptographer = state_.keystore_keys_cryptographer =
KeystoreKeysCryptographer::CreateEmpty(); KeystoreKeysCryptographer::CreateEmpty();
......
...@@ -153,13 +153,18 @@ KeyParams Pbkdf2KeyParams(std::string key) { ...@@ -153,13 +153,18 @@ KeyParams Pbkdf2KeyParams(std::string key) {
} }
KeyParams KeystoreKeyParams(const std::string& key) { KeyParams KeystoreKeyParams(const std::string& key) {
// Due to mis-encode of keystore keys to base64 we have to always encode such // base64 encoding of the keys was adopted before deriving Nigori keys because
// keys to provide backward compatibility. // the underlying crypto libraries (in particular the Java counterparts in
// JDK's implementation for PBKDF2) assume the keys are utf8.
std::string encoded_key; std::string encoded_key;
base::Base64Encode(key, &encoded_key); base::Base64Encode(key, &encoded_key);
return Pbkdf2KeyParams(std::move(encoded_key)); return Pbkdf2KeyParams(std::move(encoded_key));
} }
KeyParams TrustedVaultKeyParams(const std::string& key) {
return KeystoreKeyParams(key);
}
KeyParams ScryptKeyParams(const std::string& key) { KeyParams ScryptKeyParams(const std::string& key) {
return {KeyDerivationParams::CreateForScrypt("some_constant_salt"), key}; return {KeyDerivationParams::CreateForScrypt("some_constant_salt"), key};
} }
...@@ -1248,8 +1253,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1248,8 +1253,8 @@ TEST_F(NigoriSyncBridgeImplTest,
ShouldRequireUserActionIfInitiallyUsingTrustedVault) { ShouldRequireUserActionIfInitiallyUsingTrustedVault) {
const std::string kTrustedVaultKey = "trusted_vault_key"; const std::string kTrustedVaultKey = "trusted_vault_key";
EntityData entity_data; EntityData entity_data;
*entity_data.specifics.mutable_nigori() = *entity_data.specifics.mutable_nigori() = BuildTrustedVaultNigoriSpecifics(
BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey)}); {TrustedVaultKeyParams(kTrustedVaultKey)});
EXPECT_CALL(*observer(), OnPassphraseRequired(_, _, _)).Times(0); EXPECT_CALL(*observer(), OnPassphraseRequired(_, _, _)).Times(0);
...@@ -1304,7 +1309,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1304,7 +1309,8 @@ TEST_F(NigoriSyncBridgeImplTest,
EntityData new_entity_data; EntityData new_entity_data;
*new_entity_data.specifics.mutable_nigori() = *new_entity_data.specifics.mutable_nigori() =
BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey)}); BuildTrustedVaultNigoriSpecifics(
{TrustedVaultKeyParams(kTrustedVaultKey)});
EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, _)).Times(0); EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, _)).Times(0);
EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, _)).Times(0); EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, _)).Times(0);
...@@ -1340,8 +1346,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1340,8 +1346,8 @@ TEST_F(NigoriSyncBridgeImplTest,
EXPECT_CALL(*observer(), OnPassphraseRequired(_, _, _)).Times(0); EXPECT_CALL(*observer(), OnPassphraseRequired(_, _, _)).Times(0);
EntityData entity_data; EntityData entity_data;
*entity_data.specifics.mutable_nigori() = *entity_data.specifics.mutable_nigori() = BuildTrustedVaultNigoriSpecifics(
BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey)}); {TrustedVaultKeyParams(kTrustedVaultKey)});
ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"})); ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"}));
ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)), ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
...@@ -1356,8 +1362,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1356,8 +1362,8 @@ TEST_F(NigoriSyncBridgeImplTest,
EntityData new_entity_data; EntityData new_entity_data;
*new_entity_data.specifics.mutable_nigori() = *new_entity_data.specifics.mutable_nigori() =
BuildTrustedVaultNigoriSpecifics( BuildTrustedVaultNigoriSpecifics(
{Pbkdf2KeyParams(kTrustedVaultKey), {TrustedVaultKeyParams(kTrustedVaultKey),
Pbkdf2KeyParams(kRotatedTrustedVaultKey)}); TrustedVaultKeyParams(kRotatedTrustedVaultKey)});
EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, _)).Times(0); EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, _)).Times(0);
EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, _)).Times(0); EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, _)).Times(0);
EXPECT_CALL(*observer(), OnPassphraseTypeChanged(_, _)).Times(0); EXPECT_CALL(*observer(), OnPassphraseTypeChanged(_, _)).Times(0);
...@@ -1384,8 +1390,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1384,8 +1390,8 @@ TEST_F(NigoriSyncBridgeImplTest,
const std::string kCustomPassphrase = "custom_passphrase"; const std::string kCustomPassphrase = "custom_passphrase";
EntityData entity_data; EntityData entity_data;
*entity_data.specifics.mutable_nigori() = *entity_data.specifics.mutable_nigori() = BuildTrustedVaultNigoriSpecifics(
BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey)}); {TrustedVaultKeyParams(kTrustedVaultKey)});
ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"})); ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"}));
ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)), ASSERT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
...@@ -1425,8 +1431,8 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1425,8 +1431,8 @@ TEST_F(NigoriSyncBridgeImplTest,
const std::string kTrustedVaultKey1 = "trusted_vault_key_1"; const std::string kTrustedVaultKey1 = "trusted_vault_key_1";
const std::string kTrustedVaultKey2 = "trusted_vault_key_2"; const std::string kTrustedVaultKey2 = "trusted_vault_key_2";
EntityData entity_data; EntityData entity_data;
*entity_data.specifics.mutable_nigori() = *entity_data.specifics.mutable_nigori() = BuildTrustedVaultNigoriSpecifics(
BuildTrustedVaultNigoriSpecifics({Pbkdf2KeyParams(kTrustedVaultKey1)}); {TrustedVaultKeyParams(kTrustedVaultKey1)});
ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"})); ASSERT_TRUE(bridge()->SetKeystoreKeys({"keystore_key"}));
EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)), EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
...@@ -1444,9 +1450,9 @@ TEST_F(NigoriSyncBridgeImplTest, ...@@ -1444,9 +1450,9 @@ TEST_F(NigoriSyncBridgeImplTest,
const CryptographerImpl& cryptographer = const CryptographerImpl& cryptographer =
bridge()->GetCryptographerForTesting(); bridge()->GetCryptographerForTesting();
ASSERT_THAT(cryptographer, ASSERT_THAT(cryptographer,
CanDecryptWith(Pbkdf2KeyParams(kTrustedVaultKey1))); CanDecryptWith(TrustedVaultKeyParams(kTrustedVaultKey1)));
EXPECT_THAT(cryptographer, EXPECT_THAT(cryptographer,
Not(CanDecryptWith(Pbkdf2KeyParams(kTrustedVaultKey2)))); Not(CanDecryptWith(TrustedVaultKeyParams(kTrustedVaultKey2))));
EXPECT_THAT(cryptographer.KeyBagSizeForTesting(), Eq(size_t(1))); EXPECT_THAT(cryptographer.KeyBagSizeForTesting(), Eq(size_t(1)));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment