Hi all, I wanted to bikeshed just a little bit, to make sure there is some consensus.
tl;dr We're upgrading the password hash used to store passwords to make offline cracking more difficult. In doing that, we need to set one of the options as default. Speak up if you have strong feelings about one over the other.
Along with refactoring how passwords are stored and checked, https://gerrit.wikimedia.org/r/#/c/77645 implements two strong hashing algorithms PBKDF2 [1] and bcrypt [2]. I added a followup commit to add in the algorithm that Tim came up with in 2010 using Whirlpool as a hash function [3].
For any of these, there is a maintenance script to wrap current passwords with one of the strong ones, so we can upgrade the whole database without interaction from the users. It's also simple to upgrade the work factor or change to a new algorithm, if we decide that is needed in the future. But for the actual default...
Bcrypt is probably the most common option for password storage in webapps that I see. PHP 5.5 uses it as the default for the new password_hash() function. The only issue is that PHP before 5.3.7 had a flaw in their implementation which resulted in weak hashes. If we set bcrypt as default, we would want to raise the minimum php version to 5.3.7 (it's currently 5.3.2) for MediaWIki 1.23.
PBKDF2 is an RSA standard and is included in PHP 5.5. Tyler did an implementation in the patch to make it backwards compatible. The only downside to it is the connection to RSA, who may have knowingly standardized weak algorithms, although the security properties of PBKDF2 are fairly well studied and haven't been called into question.
The Whirlpool algorithm by Tim would force password cracking software to do a custom implementation for our hashes. It has very similar work effort to bcrypt, and should keep our passwords as safe as using bcrypt. The theory behind it seems good, but obviously, we might discover a gaping hole in it at some point.
Is there any strong preference among these options? My personal vote is for bcrypt, if bumping the php version doesn't seem like a big deal to everyone.
[1] - https://en.wikipedia.org/wiki/PBKDF2 [2] - https://en.wikipedia.org/wiki/Bcrypt [3] - http://www.mail-archive.com/wikitech-l@lists.wikimedia.org/msg08830.html
Offhand I'd say "use bcrypt", but from http://us3.php.net/password_hash --
"*Caution*
Using the *PASSWORD_BCRYPT* for the *algo* parameter, will result in the *password* parameter being truncated to a maximum length of 72 characters. This is only a concern if are using the same salt to hash strings with this algorithm that are over 72 bytes in length, as this will result in those hashes being identical."
Is the 72-byte truncation a general bcrypt problem or specific to password_hash()? Any concerns or a non-issue? Note that some non-Latin strings can only fit 24 chars in 72 bytes of UTF-8. Long enough for most passwords, but some people like passphrases. :)
-- brion
On Wed, Feb 5, 2014 at 12:53 PM, Chris Steipp csteipp@wikimedia.org wrote:
Hi all, I wanted to bikeshed just a little bit, to make sure there is some consensus.
tl;dr We're upgrading the password hash used to store passwords to make offline cracking more difficult. In doing that, we need to set one of the options as default. Speak up if you have strong feelings about one over the other.
Along with refactoring how passwords are stored and checked, https://gerrit.wikimedia.org/r/#/c/77645 implements two strong hashing algorithms PBKDF2 [1] and bcrypt [2]. I added a followup commit to add in the algorithm that Tim came up with in 2010 using Whirlpool as a hash function [3].
For any of these, there is a maintenance script to wrap current passwords with one of the strong ones, so we can upgrade the whole database without interaction from the users. It's also simple to upgrade the work factor or change to a new algorithm, if we decide that is needed in the future. But for the actual default...
Bcrypt is probably the most common option for password storage in webapps that I see. PHP 5.5 uses it as the default for the new password_hash() function. The only issue is that PHP before 5.3.7 had a flaw in their implementation which resulted in weak hashes. If we set bcrypt as default, we would want to raise the minimum php version to 5.3.7 (it's currently 5.3.2) for MediaWIki 1.23.
PBKDF2 is an RSA standard and is included in PHP 5.5. Tyler did an implementation in the patch to make it backwards compatible. The only downside to it is the connection to RSA, who may have knowingly standardized weak algorithms, although the security properties of PBKDF2 are fairly well studied and haven't been called into question.
The Whirlpool algorithm by Tim would force password cracking software to do a custom implementation for our hashes. It has very similar work effort to bcrypt, and should keep our passwords as safe as using bcrypt. The theory behind it seems good, but obviously, we might discover a gaping hole in it at some point.
Is there any strong preference among these options? My personal vote is for bcrypt, if bumping the php version doesn't seem like a big deal to everyone.
[1] - https://en.wikipedia.org/wiki/PBKDF2 [2] - https://en.wikipedia.org/wiki/Bcrypt [3] - http://www.mail-archive.com/wikitech-l@lists.wikimedia.org/msg08830.html _______________________________________________ Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
Hey,
Is the 72-byte truncation a general bcrypt problem or specific to
password_hash()? Any concerns or a non-issue? Note that some non-Latin strings can only fit 24 chars in 72 bytes of UTF-8. Long enough for most passwords, but some people like passphrases. :)
I have a 100 char password.
The Whirlpool algorithm by Tim would force password cracking software to do
a custom implementation for our hashes. It has very similar work effort to bcrypt, and should keep our passwords as safe as using bcrypt. The theory behind it seems good, but obviously, we might discover a gaping hole in it at some point.
I'm very concerned about implementing our own crypto. After all, the first rule of crypto is to not roll your own.
Cheers
-- Jeroen De Dauw http://www.bn2vs.com Don't panic. Don't be evil. ~=[,,_,,]:3 --
On Wed, Feb 5, 2014 at 1:03 PM, Brion Vibber bvibber@wikimedia.org wrote:
Offhand I'd say "use bcrypt", but from http://us3.php.net/password_hash --
"*Caution*
Using the *PASSWORD_BCRYPT* for the *algo* parameter, will result in the *password* parameter being truncated to a maximum length of 72 characters. This is only a concern if are using the same salt to hash strings with this algorithm that are over 72 bytes in length, as this will result in those hashes being identical."
Is the 72-byte truncation a general bcrypt problem or specific to password_hash()? Any concerns or a non-issue? Note that some non-Latin strings can only fit 24 chars in 72 bytes of UTF-8. Long enough for most passwords, but some people like passphrases. :)
It's an issue with bcrypt itself (only uses 18 32 bit keys). Good point.
-- brion
On Wed, Feb 5, 2014 at 12:53 PM, Chris Steipp csteipp@wikimedia.org wrote:
Hi all, I wanted to bikeshed just a little bit, to make sure there is
some
consensus.
tl;dr We're upgrading the password hash used to store passwords to make offline cracking more difficult. In doing that, we need to set one of the options as default. Speak up if you have strong feelings about one over
the
other.
Along with refactoring how passwords are stored and checked, https://gerrit.wikimedia.org/r/#/c/77645 implements two strong hashing algorithms PBKDF2 [1] and bcrypt [2]. I added a followup commit to add in the algorithm that Tim came up with in 2010 using Whirlpool as a hash function [3].
For any of these, there is a maintenance script to wrap current passwords with one of the strong ones, so we can upgrade the whole database without interaction from the users. It's also simple to upgrade the work factor
or
change to a new algorithm, if we decide that is needed in the future. But for the actual default...
Bcrypt is probably the most common option for password storage in webapps that I see. PHP 5.5 uses it as the default for the new password_hash() function. The only issue is that PHP before 5.3.7 had a flaw in their implementation which resulted in weak hashes. If we set bcrypt as
default,
we would want to raise the minimum php version to 5.3.7 (it's currently 5.3.2) for MediaWIki 1.23.
PBKDF2 is an RSA standard and is included in PHP 5.5. Tyler did an implementation in the patch to make it backwards compatible. The only downside to it is the connection to RSA, who may have knowingly standardized weak algorithms, although the security properties of PBKDF2 are fairly well studied and haven't been called into question.
The Whirlpool algorithm by Tim would force password cracking software to
do
a custom implementation for our hashes. It has very similar work effort
to
bcrypt, and should keep our passwords as safe as using bcrypt. The theory behind it seems good, but obviously, we might discover a gaping hole in
it
at some point.
Is there any strong preference among these options? My personal vote is
for
bcrypt, if bumping the php version doesn't seem like a big deal to everyone.
[1] - https://en.wikipedia.org/wiki/PBKDF2 [2] - https://en.wikipedia.org/wiki/Bcrypt [3] - http://www.mail-archive.com/wikitech-l@lists.wikimedia.org/msg08830.html _______________________________________________ Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
Am 05.02.2014 23:03, schrieb Brion Vibber:
Is the 72-byte truncation a general bcrypt problem or specific to password_hash()? Any concerns or a non-issue? Note that some non-Latin strings can only fit 24 chars in 72 bytes of UTF-8. Long enough for most passwords, but some people like passphrases. :)
-- brion
http://security.stackexchange.com/a/39852 recommends to sha256 before password_hash, but better ask Bruce Schneier:
Yes, BCrypt has an upper limit of 72 characters. It's a limitation by the Blowfish cipher itself. One way to work around it is by using SHA-256 first and then BCrypt the result. In your case it would be something like
hashpw(sha256('pass'), salt)
Where we are at it:
This en-wiki article
[2] - https://en.wikipedia.org/wiki/Bcrypt
currently lacks the important information of the password limitation. Should be added by someone who's an expert in that field.
On 02/05/2014 03:53 PM, Chris Steipp wrote:
The Whirlpool algorithm by Tim would force password cracking software to do a custom implementation for our hashes.
No judgment is passed on Tim, but rule number one of crypto is never try to roll your own unless you happen to have years and years of crypto math background, and your algorithm has been picked apart by peers over at least several months before you even tentatively put it forward.
Cryptographically secure hashes are Hard to get right, and harder to evaluate with any amount of certainty. History is littered with the dessicated failed corpses of roll-your-own crypto. :-)
-- Marc
On 06/02/14 08:17, Marc A. Pelletier wrote:
On 02/05/2014 03:53 PM, Chris Steipp wrote:
The Whirlpool algorithm by Tim would force password cracking software to do a custom implementation for our hashes.
No judgment is passed on Tim, but rule number one of crypto is never try to roll your own unless you happen to have years and years of crypto math background, and your algorithm has been picked apart by peers over at least several months before you even tentatively put it forward.
Maybe Chris's phrasing misled you: I didn't invent the Whirlpool algorithm, it was invented by Vincent Rijmen and Paulo Barreto in 2000 and is now recommended by NESSIE and ISO. My proposal was just to use str_repeat() on the input to Whirlpool in order to increase the number of Whirlpool cipher rounds without requiring a tight loop in PHP.
-- Tim Starling
On 02/05/2014 09:34 PM, Tim Starling wrote:
Maybe Chris's phrasing misled you: I didn't invent the Whirlpool algorithm
And so it did; something a quick google would have revealed. In my defense, "The Whirlpool algorithm by Tim" was pretty convincing attribution. :-)
I'd need to read up on that algorithm a bit before I have an opinion on whether length-extension attacks are not an issue with it (which is often particularly nasty when the message repeats or is cyclical). Most hashes fare better by prepending a nonce as salt than they do by padding or repeating.
-- Marc
Password hashing algorithms are not the same as general hash algorithms. I would prefer we didn't use whirlpool; it is "recommended by NESSIE and ISO" as a hash function, but as a password hash. CWE916 recommends "bcrypt, scrypt, and PBKDF2" specifically for password hashing.
To be clear, I have nothing against the Whirlpool hash algorithm itself: it's got a long pedigree with a decent amount of cryptoanalysis. It's just the extension to password hashing which is nonstandard. If you wanted to use Whirlpool as a password hash, you should apply it as part of PBKDF2, which is parameterizable. That would be a reasonable way to distinguish the WMF hash to avoid general attacks without inventing new cryptography. The default PRF for PBKDF2 is HMAC-SHA-1; you would be replacing this with HMAC-Whirpool. This would be much preferable to using str_repeat+Whirlpool. --scott
On Wed, Feb 5, 2014 at 10:00 PM, Marc A. Pelletier marc@uberbox.org wrote:
On 02/05/2014 09:34 PM, Tim Starling wrote:
Maybe Chris's phrasing misled you: I didn't invent the Whirlpool algorithm
And so it did; something a quick google would have revealed. In my defense, "The Whirlpool algorithm by Tim" was pretty convincing attribution. :-)
I'd need to read up on that algorithm a bit before I have an opinion on whether length-extension attacks are not an issue with it (which is often particularly nasty when the message repeats or is cyclical). Most hashes fare better by prepending a nonce as salt than they do by padding or repeating.
-- Marc
Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
Strictly speaking it would be best to implement PBKDF2 to accept any hash algorithm it's configured with – like I did in my password-hashing branch – rather than using just whirlpool.
I thought I even used whirlpool myself as the default in my branch, but it looks like I actually played it safe and used sha256 as the default hash algorithm with 64 bits of salt and 10000 PBKDF2 HMAC iterations.
~Daniel Friesen (Dantman, Nadir-Seen-Fire) [http://danielfriesen.name/]
On 2014-02-05 8:26 PM, C. Scott Ananian wrote:
Password hashing algorithms are not the same as general hash algorithms. I would prefer we didn't use whirlpool; it is "recommended by NESSIE and ISO" as a hash function, but as a password hash. CWE916 recommends "bcrypt, scrypt, and PBKDF2" specifically for password hashing.
To be clear, I have nothing against the Whirlpool hash algorithm itself: it's got a long pedigree with a decent amount of cryptoanalysis. It's just the extension to password hashing which is nonstandard. If you wanted to use Whirlpool as a password hash, you should apply it as part of PBKDF2, which is parameterizable. That would be a reasonable way to distinguish the WMF hash to avoid general attacks without inventing new cryptography. The default PRF for PBKDF2 is HMAC-SHA-1; you would be replacing this with HMAC-Whirpool. This would be much preferable to using str_repeat+Whirlpool. --scott
On Wed, Feb 5, 2014 at 8:26 PM, C. Scott Ananian cananian@wikimedia.orgwrote:
Password hashing algorithms are not the same as general hash algorithms. I would prefer we didn't use whirlpool; it is "recommended by NESSIE and ISO" as a hash function, but as a password hash. CWE916 recommends "bcrypt, scrypt, and PBKDF2" specifically for password hashing.
To be clear, I have nothing against the Whirlpool hash algorithm itself: it's got a long pedigree with a decent amount of cryptoanalysis. It's just the extension to password hashing which is nonstandard. If you wanted to use Whirlpool as a password hash, you should apply it as part of PBKDF2, which is parameterizable. That would be a reasonable way to distinguish the WMF hash to avoid general attacks without inventing new cryptography. The default PRF for PBKDF2 is HMAC-SHA-1; you would be replacing this with HMAC-Whirpool. This would be much preferable to using str_repeat+Whirlpool. --scott
Sorry for the misleading. "Tim's algorithm" was indeed in reference to using str_repeat vs. the tight xor loop of pbkdf2. Here are the relevant ways that each do work:
pbdkf2: for ( $j = 1; $j < $this->params['rounds']; ++$j ) { $lastRound = hash_hmac( $this->params['algo'], $lastRound, $password, true ); $roundTotal ^= $lastRound; }
Tim's: for ( $i = 0; $i < $iter; $i++ ) { $h = hash( 'whirlpool', str_repeat( $h . $this->args[0], 100 ), true ); $h = substr( $h, 7, 32 ); }
If you look at whirlpool's compression function for the long messages, and see that pbdkf2 as pretty much a Davies-Meyer compression function, they have very similar properties. Except where they're subtly different, of course ;).
The first subtle difference that I like about pbkdf2 is that the password is mixed in at each round throughout, whereas Tim only mixes it in directly in the first iteration (which is roughly the same as 3 rounds of pbkdf2 for an 8 character password and 8 byte salt, since whirlpool is operating on 512-bit blocks). This could make pbkdf2 weaker if a key recovery attack suddenly showed up in the hmac function, although that seems very unlikely for hmac-sha256.
Additionally, since Tim's assigns the output to $h instead of xoring into the previous round, that would be the same as pbkdf2 doing an assignment every 14 rounds, which would feel a little weaker to me. Tim's could be updated to keep the last block and do an xor instead, and they would be more similar.
For someone doing a custom crypto scheme, I think Tim does better than most, but overall it seems like most people prefer complying with a well recommended standard than being unique.
So far no one has said they dislike pbkdf2, while bcrypt would require an extra hash in serial to make sure long passwords can be handled, and would require the php version bump. Anyone have strong opinions against pbkdf2?
On Wed, Feb 5, 2014 at 10:00 PM, Marc A. Pelletier marc@uberbox.org wrote:
On 02/05/2014 09:34 PM, Tim Starling wrote:
Maybe Chris's phrasing misled you: I didn't invent the Whirlpool algorithm
And so it did; something a quick google would have revealed. In my defense, "The Whirlpool algorithm by Tim" was pretty convincing attribution. :-)
I'd need to read up on that algorithm a bit before I have an opinion on whether length-extension attacks are not an issue with it (which is often particularly nasty when the message repeats or is cyclical). Most hashes fare better by prepending a nonce as salt than they do by padding or repeating.
-- Marc
Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
-- (http://cscott.net) _______________________________________________ Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
Hey,
I just stumbled across this wrapper [0] for the password functions introduced in PHP 5.5. Figured this stuff is also relevant in the discussion.
[0] https://github.com/ircmaxell/password_compat [1] http://de1.php.net/password
Cheers
-- Jeroen De Dauw http://www.bn2vs.com Don't panic. Don't be evil. ~=[,,_,,]:3 --
tl;dr PBKDF2 and bcrypt are both perfectly acceptable for security.
PBKDF2 and bcrypt, as well as scrypt, are all well regarded by current infosec industry standards (with "current" being a key word). " While there is active debate about which of these is the most effective, they are all stronger than using salts with hash functions [that have] very little computing overhead" (CWE 916). Feel free to use whichever one best meets the project needs in terms of implementation, user version migration, etc.
Custom crypto algorithms should indeed always be completely off the table, including any (supposed) "minor" custom modifications to crypto standards. Indeed, custom _implementations_ themselves are best to be avoided in favor of established libraries whenever possible.
I had not heard of Whirlpool before. While (based on WP) the algo has a reputable designer, hashes can be built for different purposes, and the WP page does not appear to indicate that this one was designed for the purpose of strengthening the difficulty to crack. Indeed, the phrase "... was changed ... to one which ... is easier to implement in hardware" is an _undesirable_ quality when it comes to the goal of key stretching.
Note that much confusion on the web about key lengths with bcrypt ("72" vs. "56" bytes) comes from the fact that there are TWO algorithms called "bcrypt" which both happen to use Blowfish. One is an encryption algorithm, and the other is a hash algorithm. While they share a common core component, the purposes are thereby entirely different. For the sake of the bcrypt HASHING/key-strengthening algorithm (which we care about now), the 72-byte input parameter is in no way a theoretical problem at all, even for non-Latin UTF-8 based passphrases which eat up 3 bytes per unicode point. The reason is because the text-based passphrase itself needs to "somehow" be converted into 18 words of 32-bits each anyway. (If we were _encrypting_ then the 56 bytes limit for THAT algorithm would come into play.) Even if you restrict your attention to ASCII it would not be ideal to simply convert ASCII code points to a (zero-padded) juxtaposed stream of 32-bit chunks anyway, because, well for one thing, you would be throwing away entropy due to not using the upper 1-bit range in each char, not to mention the range of unavailable non-printable ASCII characters. As noted on WP:bcrypt, "Mapping of password to input is unspecified in the original revision of bcrypt." So, despite the strict no-custom-crypto principle already noted, the "passphrase to bcrypt input" mapping is one place where the standard leaves you to just use practical smarts. Seeking to optimize the entropy range in this stage is almost certainly overkill anyway. Still, I believe we can do better than a "truncation of utf-8 text encoding" rule without great trouble.
References: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet http://cwe.mitre.org/data/definitions/916.html (Use of Password Hash With Insufficient Computational Effort) https://cwe.mitre.org/data/definitions/327.html ( ... Do not develop custom or private cryptographic algorithms) https://bugzilla.wikimedia.org/show_bug.cgi?id=28419 (Re: The Whirlpool recommendation) https://en.wikipedia.org/wiki/Whirlpool_(cryptography) http://en.wikipedia.org/wiki/Bcrypt (Note reference to the "other" bcrypt algorithm near the bottom of External Links)
-Zach Harris, PhD Secure Code Analyst
On Wed, Feb 5, 2014 at 3:08 PM, Zachary Harris zacharyharris@hotmail.comwrote:
tl;dr PBKDF2 and bcrypt are both perfectly acceptable for security.
PBKDF2 and bcrypt, as well as scrypt, are all well regarded by current infosec industry standards (with "current" being a key word). " While there is active debate about which of these is the most effective, they are all stronger than using salts with hash functions [that have] very little computing overhead" (CWE 916). Feel free to use whichever one best meets the project needs in terms of implementation, user version migration, etc.
Custom crypto algorithms should indeed always be completely off the table, including any (supposed) "minor" custom modifications to crypto standards. Indeed, custom _implementations_ themselves are best to be avoided in favor of established libraries whenever possible.
I had not heard of Whirlpool before. While (based on WP) the algo has a reputable designer, hashes can be built for different purposes, and the WP page does not appear to indicate that this one was designed for the purpose of strengthening the difficulty to crack. Indeed, the phrase "... was changed ... to one which ... is easier to implement in hardware" is an _undesirable_ quality when it comes to the goal of key stretching.
Note that much confusion on the web about key lengths with bcrypt ("72" vs. "56" bytes) comes from the fact that there are TWO algorithms called "bcrypt" which both happen to use Blowfish. One is an encryption algorithm, and the other is a hash algorithm. While they share a common core component, the purposes are thereby entirely different. For the sake of the bcrypt HASHING/key-strengthening algorithm (which we care about now), the 72-byte input parameter is in no way a theoretical problem at all, even for non-Latin UTF-8 based passphrases which eat up 3 bytes per unicode point. The reason is because the text-based passphrase itself needs to "somehow" be converted into 18 words of 32-bits each anyway. (If we were _encrypting_ then the 56 bytes limit for THAT algorithm would come into play.) Even if you restrict your attention to ASCII it would not be ideal to simply convert ASCII code points to a (zero-padded) juxtaposed stream of 32-bit chunks anyway, because, well for one thing, you would be throwing away entropy due to not using the upper 1-bit range in each char, not to mention the range of unavailable non-printable ASCII characters. As noted on WP:bcrypt, "Mapping of password to input is unspecified in the original revision of bcrypt." So, despite the strict no-custom-crypto principle already noted, the "passphrase to bcrypt input" mapping is one place where the standard leaves you to just use practical smarts. Seeking to optimize the entropy range in this stage is almost certainly overkill anyway. Still, I believe we can do better than a "truncation of utf-8 text encoding" rule without great trouble.
Yes, we can hash the password first
References: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet http://cwe.mitre.org/data/definitions/916.html (Use of Password Hash With Insufficient Computational Effort) https://cwe.mitre.org/data/definitions/327.html ( ... Do not develop custom or private cryptographic algorithms) https://bugzilla.wikimedia.org/show_bug.cgi?id=28419 (Re: The Whirlpool recommendation) https://en.wikipedia.org/wiki/Whirlpool_(cryptography) http://en.wikipedia.org/wiki/Bcrypt (Note reference to the "other" bcrypt algorithm near the bottom of External Links)
-Zach Harris, PhD Secure Code Analyst
Wikitech-l mailing list Wikitech-l@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/wikitech-l
wikitech-l@lists.wikimedia.org