New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 820976 link

Starred by 34 users

Issue metadata

Status: Started
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , iOS , Chrome , Mac , Fuchsia
Pri: 2
Type: Bug

Blocked on:
issue 875901


Show other hotlists

Hotlists containing this issue:
Hotlist-1


Sign in to add a comment

Security: Chrome Sync passphrase is far too easy to bruteforce

Reported by wladi...@palant.de, Mar 12 2018

Issue description

VULNERABILITY DETAILS
Documentation https://support.google.com/chrome/answer/165139#passphrase states the following:

> With a passphrase, you can use Google's cloud to store and sync your Chrome data without letting Google read it.

That's not currently true. The encryption key for the data is derived from the passphrase using PBKDF2-HMAC-SHA1 using a fixed salt and merely 1003 iterations. This doesn't provide significant protection against bruteforcing the passphrase. Worse yet, if somebody manages to access encrypted data from multiple user accounts, the fixed salt allows bruteforcing all of them at the same time.

The sequence in code is the following:

* SyncEncryptionHandlerImpl::SetCustomPassphrase(passphrase), https://cs.chromium.org/chromium/src/components/sync/engine_impl/sync_encryption_handler_impl.cc?l=1110&rcl=bddb211b216ed6844cb64a7ec51b069e0ac044b5
* Cryptographer::AddKey({"localhost", "dummy", passphrase}), https://cs.chromium.org/chromium/src/components/sync/base/cryptographer.cc?l=160&rcl=bddb211b216ed6844cb64a7ec51b069e0ac044b5
* Nigori::InitByDerivation("localhost", "dummy", passphrase), https://cs.chromium.org/chromium/src/components/sync/base/nigori.cc?l=65&rcl=bddb211b216ed6844cb64a7ec51b069e0ac044b5

InitByDerivation() will derive a salt first. Given that the input is fixed however, that salt is a constant: Suser = PBKDF2("localhostdummy", "saltsalt", 1001, 8). It will then derive the encryption key as Kenc = PBKDF2(passphrase, Suser, 1003, 16). So in order to find any Google Sync accounts using "password1" as passphrase, an attacker would only need to derive an encryption key from that passphrase once and try to decrypt the data for any accounts it can access.

Even with a salt that isn't fixed but rather based on account ID for example, 1003 iterations are a way too low hurdle today. Judging by the numbers provided in https://blog.codinghorror.com/hacker-hack-thyself/, a single Nvidia GTX 1080 GPU would be able to calculate 3.2 million PBKDF2-HMAC-SHA1 hashes with 1003 iterations per second. That's enough to go through the enormous list of passwords under https://crackstation.net/buy-crackstation-wordlist-password-cracking-dictionary.htm in less than 8 minutes. Even the passphrase of users who didn't reuse passwords and chose a passphrase with 40 bits of entropy (that's already stronger than most of them) would be guessed within two days.

I'd consider 256,000 PBKDF2-HMAC-SHA1 iterations or 100,000 PBKDF2-HMAC-SHA256 iterations the bare minimum that is still acceptable today. And each user should have their individual salt of course.
 
Components: Security Services>Sync Privacy
Labels: -Type-Bug-Security -Restrict-View-SecurityTeam Type-Bug
On an external post is also this note that probably bears fixing at the same time, but isn't a security issue:

"The function in question manages to run PBKDF2 four times where one run would have been sufficient. First run derives the salt from host name and username (both happen to be constants in case of Chrome Sync). This is pretty pointless: a salt doesn’t have to be a secret, it merely needs to be unique. So concatenating the values or running SHA-256 on them would do just as well. The next three runs derive three different keys from identical input, using different iteration counts. A single PBKDF2 call producing the data for all three keys clearly would have been a better idea."

Comment 3 by jkrcal@chromium.org, Mar 20 2018

Cc: jkrcal@chromium.org

Comment 4 by mkwst@chromium.org, Mar 23 2018

Cc: tschumann@chromium.org battre@chromium.org
tschumann@: Mind triaging this from the sync perspective?

battre@, FYI.

Comment 5 by treib@chromium.org, Mar 26 2018

Cc: -tschumann@chromium.org
Owner: tschumann@chromium.org
Status: Assigned (was: Unconfirmed)

Comment 6 by palmer@chromium.org, Apr 19 2018

Cc: tschumann@chromium.org
Labels: M-69 OS-Android OS-Chrome OS-Fuchsia OS-iOS OS-Linux OS-Mac OS-Windows Pri-1
Owner: palmer@chromium.org
Status: Started (was: Assigned)
Just to kickstart the process, I put up a CL here: https://chromium-review.googlesource.com/c/chromium/src/+/1018489 It probably won't work as-is, but hopefully we can do a sort of stone soup thing (https://en.wikipedia.org/wiki/Stone_Soup). :)

Comment 7 by treib@chromium.org, Apr 30 2018

Cc: palmer@chromium.org
Owner: vitaliii@chromium.org

Comment 8 by t...@tillulen.com, May 7 2018

Could you please use Argon2 or scrypt instead of PBKDF2?
Thank you for your suggestion! We are already looking at using something else than PBKDF2, however, the outcome is not clear yet, because there are multiple factors at play.
Ping: Any updates on this?
There seem to be a consensus to use scrypt instead.
The parameter selection happened to be harder than I thought (mainly because of memory). I need to do some benchmarking and check with people knowing more about memory on Android. 
Labels: -Pri-1 Pri-2
Triage ping. Does this target M69? It seems too optimistic.
It does target M69, the BP is on 19th of July.
I am meeting with Android Chrome folks tomorrow.
Issue 686929 has been merged into this issue.
sync-triage ping: any updates?
Labels: -M-69 M-70
I've reached an agreement with the security team, I need to polish the design doc, get more approvals and start implementing.

I hope that the first implementation will be in M70.
However, we won't enable it in M70 due to backward incompatibility and will wait for at list 2 milestones.
Owner: davidovic@google.com
Blockedon: 875901
The optimistic plan for the implementation is still M70.
The launch itself can be done in M71 or M72 (depending on how much backward incompatibility can we allow).

davidovic@ is starting the implementation.
Issue 875901 is a tracking bug (sorry, Google-internal only).
Hi,

We have the code ready (scrypt) in M70, but it is currently completely disabled, because the testing wasn't finished yet.

Please note that the change is not backward compatible (the data encrypted with the scrypt derived key cannot be decrypted in <=M69, any (even a valid) passphrase will be rejected). In order to mitigate this, we will wait until M72 before enabling the new key derivation method. Then users on >=M70 will be able to decrypt data encrypted with scrypt derived key.
#19: Is it possible to use a "fallback" scheme? E.g.:

```
key = new_key_derivation(passphrase)
error = decrypt(key, data)
if (error) {
  key = old_key_derivation(passphrase)
  error = decrypt(key, data)
  if (error) {
    return error
  }
}

use_data(data)...
```

#20: We are already doing that (via a different but equivalent mechanism). The problem is that we need, at some point, to flip the switch that will cause newly-set passphrases to use the new key derivation method. Once we do that, old versions of Chrome (<M70) will not be able to access this data, simply because they know nothing about the new method. They will blindly try using the old one, see that they're unable to decrypt the data, and surface an "Incorrect passphrase" error to the user. Short of backporting the scrypt code to <M70 (which is impossible), we can do nothing about that. The best we can do is delay flipping the switch until a majority of users are using >=M70, which is the first version that is able to handle key derivation using both new and old methods.
To #20: Your example handles "new versions of Chrome understanding old data" case, which we do indeed already support. 

The backward incompatibility example:
1) User updates to M72 on their desktop, but their phone is still M69.
2) We enable the new key derivation method in M72. 
3) User sets a new custom passphrase on their desktop.
4) User cannot decrypt the data on their phone unless they update. The message they will see is that the passphrase is wrong.

On the other hand, if user sets a custom passphrase from their phone (M69), everything will work as expected.
Cc: ayatane@chromium.org
Labels: Hotlist-ConOps-CrOS
Owner: vitaliii@chromium.org

Sign in to add a comment