[cryptography] Javascript Password Hashing: Scrypt with WebCrypto API?

Jeffrey Goldberg jeffrey at goldmark.org
Thu Mar 12 12:57:47 EDT 2015


Leaving aside the “Crypto in JS delivered over the web: Don’t do it”, I will offer
a couple of suggestions.

> at GlobaLeaks we're undergoing implementation of client-side encryption
> with server-side storage of PGP Private keys.

I understand why you are looking for ways to make this less scary. As you
probably know, this makes your servers a very juicy target.

> Obviously the hashing to be used for storing such PGP private keys has
> to be strong enough, with valuable key-stretching approach.

Yes. Though I’m not sure that hashing will be enough.

> We're now considering using Scrypt with some finely tuned parameters,
> but we've concern regarding it's performance in the browser as a JS
> implementation.

Yes. That is going to be a problem (I will offer an alternative approach
below)

> PBKDF2 is available from WebCrypto API

I don’t know that your time-line is, but it I believe that only
Chrome Canary actually implements this at the moment.


> and, as far as i read and
> understand but i'm not that low-level-crypto expert, is used internally
> to scrypt.

Although scrypt makes some use of PBKDF2, you won’t be able to
simply build scrypt out of PBKDF, nor will you be able to build 

> Does anyone know of any scrypt implementation that try to leverage the
> WebCrypto API?

Even if you need the whole client-side crypto delivered in the browser,
I don’t think that you will find scrypt in JS useful, as the performance means
that you will not be able to put set parameters in a way that will thwart the
kinds of attackers that you can expect.

So I’m going to make multiple proposals that can be adopted independently
of each other.

1. Split password hashing between server and client.

Have the client do as many PBKDF2 rounds as you can get away with, and then
use the result of that as a input to your use of scrypt server side.

2. Use SHA-512 in PBKDF2

This will make PBKDF2 resistant to GPU based cracking efforts.
Note that this is resistance to attacks using current, off-the-shelf, 
hardware. It is only a short term solution.

3. Use a second factor.

Client side, you can combine the processing of the user’s password
with some data from some second factor (stored in a file on a USB
device or the like). Of course if they lose that data, they will be locked
out forever.

This is really the thing that will make it impossible for attackers
who get copies of your stored data to be able to decrypt what you
have stored.

A couple of notes:

Things like PBKDF2 and scrypt will never protect you from
well-resourced attackers. This is because the cost to both the
defender and the attacker are of the same order. And so, that gives
the advantage to those who can through more resources at the task.
As computing gets cheaper, the advantage shits towards the attacker.
This is unlike what we have with security factors of other sorts of things,
where the work needed by the attacker rises exponentially compared to the
polynomial cost to the defender.

You are correct to want client-side crypto, but because you are delivering
the crypto from the web, you are not providing the benefits of client side
crypto. Someone who gains control of the server you deliver the JS from
or gains control in transmission can deliver a malicious client to the user
and capture everything they need.

This isn’t about JavaScript, but it is about how easy it is for an attacker
(or you) to provide a malicious client to your users.

Cheers,

-j






More information about the cryptography mailing list