New issue
Advanced search Search tips
Starred by 24 users

Issue metadata

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


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

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."
Cc: jkrcal@chromium.org
Cc: tschumann@chromium.org battre@chromium.org
tschumann@: Mind triaging this from the sync perspective?

battre@, FYI.
Cc: -tschumann@chromium.org
Owner: tschumann@chromium.org
Status: Assigned (was: Unconfirmed)
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). :)
Cc: palmer@chromium.org
Owner: vitaliii@chromium.org
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. 

Comment 12 by mastiz@chromium.org, Jun 20 (3 days ago)

Labels: -Pri-1 Pri-2
Triage ping. Does this target M69? It seems too optimistic.

Comment 13 by vitaliii@chromium.org, Jun 20 (3 days ago)

It does target M69, the BP is on 19th of July.
I am meeting with Android Chrome folks tomorrow.

Sign in to add a comment