argon2 PasswordHasher

398 views
Skip to first unread message

Bas Westerbaan

unread,
Dec 26, 2015, 6:36:02 PM12/26/15
to Django developers (Contributions to Django itself)
Hello,

This morning I submitted a Pull Request[1], which adds a PasswordHasher for argon2 – the winner of the Password Hashing Competition.[2]  Tim Graham mentioned I should send an e-mail to this list to discuss it.

The patch is mostly pretty straight-forward.  I would like to add a few remarks on some of the choices.

1. There are two Python packages that implement argon2.  Both bind libargon2[3].  The first is argon2_py[4], which uses ctypes.  The second is argon2-cffi[5], which uses... cffi.  Bindings using cffi are more portable, so I choose argon2-cffi.

2. argon2 has four parameters: (i) variety ("type"), (ii) time cost ("t"), (iii) memory cost ("m") and (iv) parallelism ("p").  There are two varieties: argon2i and argon2d.  The first (argon2i) is safest against side-channel attacks.  The second tries less hard to be secure against side-channel attacks in favour of being more resilient against GPU brute-forcing.  For web-apps, the first "argon2i" is the clear choice.  For the other parameters I choose to use the same defaults as of argon2-cffi: t=2, m=512, p=2.  On a i7-4790 @ 3.6Ghz the hash takes around 2ms to compute.

Best wishes,

  Bas



Florian Apolloner

unread,
Dec 27, 2015, 7:39:21 AM12/27/15
to Django developers (Contributions to Django itself)
I do not see anything wrong in the PR and there is probably no reason not to include it. It would be great if you could get feedback from dstufft and/or hynek in #cryptography-dev -- not that we miss something.

Cheers,
Florian

Bas Westerbaan

unread,
Jan 3, 2016, 8:52:25 AM1/3/16
to django-d...@googlegroups.com
Hynek weighted in[1].  I think the PR is ready to merge.

Best wishes,

-- 
You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/NTfqP4eNVyA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/9a3378d2-3a8b-4bd9-b1e0-d64e25475d02%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bas Westerbaan

unread,
Jan 29, 2016, 5:01:21 AM1/29/16
to django-d...@googlegroups.com
Hi all,

The PR[1] that adds Argon2 as a PasswordHasher is ready to be merged.  It does not make Argon2 the default.  The reasons not to make it the default are:

1. Argon2 is young.  (Its design, though, is uncontroversial.)
2. Argon2 requires C-bindings and thus does not work on every platform Django wants to support.

I like to discuss how to take away the last concern.

We could make Argon2 the default on a system if the C-bindings are available and otherwise fallback to PBKDF2.[2]  The problem is that it might happen that switching servers Argon2 might become unavailable and so users might not be able to log-in anymore.  To solve this, I wrote a pure Python implementation of Argon2.[3]  It it quite a bit slower[4] than the C-version and so I suggest to only use it to switch to another PasswordHasher if the C-version of Argon2 isn’t available anymore.[5]

What do you think?

Best,

  Bas


---
[2] Maybe add an `should_be_used’ field to the class and skip PasswordHasher’s for which this is False.
[4] The Argon2 hash in the PR takes ~5ms in C and ~1.3s in Python.  Having to wait 1.3s once per user to change to another PasswordHasher is, I guess, acceptable.  (There is still a lot of room for optimisation.  Maybe it could go down to ~100ms, but probably not any more.)
[5] Maybe add an `can_be_used’ field to PasswordHasher to indicate that even though it should not be used as default, it can still verify.

Marc Tamlyn

unread,
Jan 29, 2016, 9:45:11 AM1/29/16
to django-d...@googlegroups.com
I may not understand the security implications here properly, but as far as I can tell there isn't a strong enough case that Argon2 is fundamentally better than PBKDF2 yet? At least no more than people's arguments that BCrypt is better. I think retaining the simple out of the box experience where you get good, performant enough password hashing is important. I'd say 1.3 seconds is fundamentally *not* fast enough. If someone upgrades their site to Django 1.10 without noticing the change and we force this upgrade the suddenly every user's login to the site costs 1.3 seconds - that's an enormous amount of server load.

M

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.

To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

Bas Westerbaan

unread,
Jan 29, 2016, 9:56:20 AM1/29/16
to django-d...@googlegroups.com
I may not understand the security implications here properly, but as far as I can tell there isn't a strong enough case that Argon2 is fundamentally better than PBKDF2 yet?

Barring any weakness in Blake2 we do not know about, Argon2 is way better than PBKDF2 as it is memory-hard.  The gap between SHA256 and PBKDF2 and PBKDF2 and Argon2 (with Django’s settings) might be of comparable order of magnitude as I outlined in this comment[1].

I'd say 1.3 seconds is fundamentally *not* fast enough. If someone upgrades their site to Django 1.10 without noticing the change and we force this upgrade the suddenly every user's login to the site costs 1.3 seconds - that's an enormous amount of server load.

That’s not my suggestion.  Sorry I did state it clearly enough.  This 1.3 second login will only happen if the server used to be able to use the fast C-argon2 library, but then can’t use it anymore.  This 1.3 second login will only happen once per user: Django would then switch back to PBKDF2.  A 1.3 second login once per user seems acceptable.  (Off course it’s not acceptable if it would happen every time the user logs in.)

Best,

  Bas


Marc Tamlyn

unread,
Jan 29, 2016, 10:07:25 AM1/29/16
to django-d...@googlegroups.com
It is once per user, but it's once for *EVERY* user when that scenario occurs. That could easily bring a site down if sessions were invalidated or you have short session times. It's far too likely someone will have serious, hard to debug problems as a result of this magical behaviour.

I also strongly agree with Carl's comment on the PR: Automatic changes in behaviour based only on the presence or absence of a third-party package (or C bindings) are questionable in general. We can (and by the sounds of it should) recommend this hasher strongly, but I don't think we need to make it the default. Unlike SHA256, PBKDF2 isn't a BAD choice yet, it's just not the best available.

There's an argument for updating the default project template for new projects, but that would make setup for new users a lot harder so I don't really like that idea either.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

Bas Westerbaan

unread,
Jan 29, 2016, 12:30:26 PM1/29/16
to django-d...@googlegroups.com
Hi Marc,

To be clear, I think we shouldn't make Argon2 the default just yet. I
would rather add it as an option for now and make it the default in a
later release. However, I would like to discuss what would block making
Argon2 the default already.


> It is once per user, but it's once for *EVERY* user when that scenario
> occurs. That could easily bring a site down if sessions were invalidated or
> you have short session times. It's far too likely someone will have
> serious, hard to debug problems as a result of this magical behaviour.

This is indeed a corcern for big websites.

What if we make the sudden absense of a C-argon2 a hard error which
includes instructions to enable the fallback behavior I described?
(To be clear: the absense of C-argon2 would only be an error if it has
actually been used as a password hash --- not if it has never been used.)


> There's an argument for updating the default project template for new
> projects, but that would make setup for new users a lot harder so I don't
> really like that idea either.

How is this different than making Argon2 the default?

Why would the setup be harder?


> I also strongly agree with Carl's comment on the PR: Automatic changes in
> behaviour based only on the presence or absence of a third-party package
> (or C bindings) are questionable in general.

Would bundling argon2-cffi with Django be an option?


> We can (and by the sounds of
> it should) recommend this hasher strongly, but I don't think we need to
> make it the default. Unlike SHA256, PBKDF2 isn't a BAD choice yet, it's
> just not the best available.

I agree, PBKDF2 is not a bad choice if there is a proper password policy in
place. I also do not want to suggest there is an immediate problem.
Maybe it is helpful to look at a real-world example. On this site[1]
two huge sets (the "GMail" and the "10 million" set) are analyzed. The
average entropy of these passords appears to be 21.6 bits. At the
moment, Django's PBKDF2 uses 60,000 iterations of SHA256. The ASIC
"AntMiner S7" computes 4000 million SHA-256 per Joule. Thus a similar
ASIC for PBKDF2 would be able to compute ~2^37 PBKDF2's per kWh. Thus,
breaking a single 37 bit PBKDF2 would set you back $0.12 (if you have
already such an ASIC).

Ok, not every attacker has the budget to develop ASICs. Suppose our
average Joe attacker has just a GPU. According to [2] a cheap AMD7750
gives you 2.66 million SHA-256 per Joule. That ~2^27 PBKDF2s for $0.12.
Our average 21.6 bit password is cheap to break using PBKDF2.

On my i7-4790 Django's PBKDF2 takes 75ms. If we pick parameters for
Argon2 such that it also takes 75ms to compute, it will compute
0.3 argon2 per Joule. That ~2^20 Argon2 for $0.12. (To be fair,
probably some Atom will be more efficient for this than an i7.)

So even Argon2 won't prevent the average password to be cheaply cracked.
If you follow XKCD's advice and use a "correct horse battery staple"
password of 44 bits, then cracking it will cost (as above)

if hashed with PBKDF2 and cracked with that ASIC $15.36
if hashed with PBKDF2 and cracked with that GPU $15728
if hashed with Argon2 and cracked with my i7 $2013265

(Even though Argon2 is designed to be hard to compute for ASICs, they
might still do a better job than a general purpose CPU: the difference
above might be smaller.)

Best,

Bas


[1] http://wpengine.com/unmasked/
[2] https://en.bitcoin.it/wiki/Non-specialized_hardware_comparison

Reply all
Reply to author
Forward
0 new messages