5 ms·
> What this clearly demonstrates, is that the only factor driving execution time, is the number of iterations you apply to the password, before delivering the f
by peeters 8y ago
> What this clearly demonstrates, is that the only factor driving execution time, is the number of iterations you apply to the password, before delivering the final password hash.
Isn't the reason this is true that bcrypt just truncates the input at 72 characters? And if that's correct, aren't there basically a few options, any of which basically invalidate the argument?
1. Enforce a password length limit. Fixes the unbounded growth of the shacrypt CPU time while simultaneously ensuring bcrypt is not ignoring input.
2. Pre-hash the input to bcrypt by passing it through SHA512. Makes bcrypt now grow in the exact same way as shacrypt.
3. Don't enforce a password limit, but truncate the password. Fixes the CPU time.
I don't know enough about bcrypt in practice to know which of those options is most commonly advised, but it just seems like a bit of a strawman here. Passing 4096 bytes to bcrypt is the same as passing 72 bytes to bcrypt because it ignores the last 4024 bytes right?
- minitech 8y ago> Pre-hash the input to bcrypt by passing it through SHA512. Makes bcrypt now grow in the exact same way as shacrypt. The pre-hash is only applied once, so the change in runtime is linear and very small compared to bcrypt.
- peeters 8y agoEdit: I stand corrected, the summary in the link below didn't agree with the more detailed steps it went into below. While the hash is used as the input to the next round, it is (for reasons beyond my understanding) repeated if necessary to match the length of the original password. But it still seems like if you're prehashing in both cases the performance issue goes away. Is that true? I thought shacrypt stretching worked by passing the output of a round of hashing as the input to the next round of hashing, so it would go from 4096 bytes to 64 bytes (e.g.) after the first round. That's how it's explained here: https://www.vidarholen.net/contents/blog/?p=33 https://www.vidarholen.net/contents/blog/?p=33. I'd love to be proven wrong. So it seems shacrypt and bcrypt would be equivalent. Do the expensive work from 4096 to <72 once, then subsequent rounds are all on the same size of input. I think my point stands, this is comparing apples and oranges unless you pre-hash the input to bcrypt and include that in the benchmark.
- Dylan16807 8y agoUsers of sha256crypt and users of bcrypt should all be pre-hashing. That doesn't mean the argument is invalid, it's just flaws to work around.
- zaarn 8y agoTbh I think prehashing should always be done (though not even I do it in practise, especially when I push something through pbkdf2 anyway) It turns any password into an equal size string which makes your password backend a lot more predictable in code (IMO).
- atoponce 8y ago> Isn't the reason this is true that bcrypt just truncates the input at 72 characters? And if that's correct, aren't there basically a few options, any of which basically invalidate the argument? Let's run a scenario to show by bcrypt from strictly a CPU load perspective is better than sha256/512crypt. > 1. Enforce a password length limit. Fixes the unbounded growth of the shacrypt CPU time while simultaneously ensuring bcrypt is not ignoring input. Assume that I know how many authentications per second are happening on my busy authentication server, and I can reliably guarantee 0.25 seconds per request without creating an outage. On my hardware, that's a bcrypt cost of 12. If I pre-hash every password with SHA-256, then base64 encode the hash, and send that to bcrypt, I can guarantee every user any arbitrary length of password, and know that it will not take more than 0.25 seconds. For sha256crypt, a cost of 250,000 rounds is similar in performance for an 8-character password, executing in about 0.250158 seconds. However, and 36-character Diceware passphrase takes about 0.353884 seconds, and grows from there (70 characters at 0.503353 seconds, etc). Obviously, I can't allow everyone to have 36-character Diceware passphrases with a sha256crypt cost of 250,000 rounds. It would create load problems on my hardware. I have three options that I see ahead of me if I wanted to stick with sha256crypt: 1. I could decrease the sha256crypt rounds, so those who want longer passwords won't create a CPU outage due to load. 2. Enforce maximum password length limit of 35 characters, to prevent the execution time from taking too long. 3. Make some exceptions in the code, so those with 1-10 characters have a higher sha256crypt cost than those with 11-24, which is still higher than those with 25-36, etc. If I just stick bcrypt on the server with a cost of 12, I don't have handle these exceptions. > 2. Pre-hash the input to bcrypt by passing it through SHA512. Makes bcrypt now grow in the exact same way as shacrypt. No it doesn't. In the graphs on my post, the bcrypt timings are based on https://passlib.readthedocs.io/en/stable/lib/passlib.hash.bcrypt_sha256.html https://passlib.readthedocs.io/en/stable/lib/passlib.hash.bc.... bcrypt only grows when the cost is increased. Its execution times are in no way affected by password length. > 3. Don't enforce a password limit, but truncate the password. Fixes the CPU time. This is a bad design, and falls back to the security vulnerabilities of DES-Crypt and LM hashes. > Passing 4096 bytes to bcrypt is the same as passing 72 bytes to bcrypt because it ignores the last 4024 bytes right? Unless you bcrypt(base64(sha-256(password))), which is a common approach.
- peeters 8y ago