== in python will stop comparing after the first character mismatch. You can use that fact to test byte by byte your password knowing that the more good characters you have, the longer the comparison will take, which is called a timing attack.
hmac.compare_digest is a constant time compare, in that no matter if there is a match or not, it will take the same amount of time.
If the attacker knows which algorithm and work factor you're utilising and your system doesn't use randomly generated per user salts (or an unknown pepper) then theoretically an attacker could use a hash timing attack, combined with a rainbow table, to massively reduce the scope of a user's potential password.
For example, let's say your rainbow table has 20 million password-hash combinations and your hash length is 33 letters, for every letter I know I could drop literally millions of hashes I know it ISN'T. With just the first four letters I could drop it by almost 60% (although my maths here might be completely wrong, it is actually pretty complicated to determine). But there's no real limit on how many letters you could drop from the hash with a timing attack, you could turn someone's password into a 1 in 62 chance.
The TL;DR: Use a per user salt. But a timing immune comparison definitely is "defense in depth" in case there is a bug elsewhere that breaks salts.
I chose the words "password hash" carefully. If you're using a secure password hash, you're not worrying about salts, because they take care of randomization for you. If you are worrying about salts, you probably have bigger problems than memcmp timing.
I literally don't understand what it is you're getting at.
Password hashing has existed since at least the 1970s and until the 2000s salting wasn't common. While some hashing libraries do insist on you supplying a salt, it is still ultimately up to the application developer to generate and store the salt for later usage.
Therefore it is still common for an application developer to "worry about salts" even if just for storage and generation reasons.
Anyone using 3DES, MD5, or similar is likely vulnerable to timing attacks, and they're definitely still in the realm of a "password hash." Plus some wonderful developers hard code the salt (salt = "secret") which too could leave them vulnerable to timing attacks if an attacker knew what hashing algorithm and workfactor (e.g. the default) was in usage.
"Password hashing" is its own compound noun. The acceptable algorithms (as defined in the blog post this HN thread is about) take care of this for you.
> Anyone using 3DES, MD5, or similar is likely vulnerable to timing attacks, and they're definitely still in the realm of a "password hash."
3DES is a block cipher. MD5 is a crytographic hash. Neither of them are password hashes.
> Plus some wonderful developers hard code the salt (salt = "secret") which too could leave them vulnerable to timing attacks if an attacker knew what hashing algorithm and workfactor (e.g. the default) was in usage.
> 3DES is a block cipher. MD5 is a crytographic hash.
3DES is both a block cipher and a cryptographic hash. At least UNIX thought so in the 1990s as many MANY people were storing UNIX passwords in 3DES, DES, MD5, and similar.
> Neither of them are password hashes.
25 years of computing history would disagree with you. MD5 was the defacto standard for password hashing for almost fifteen years.
But no doubt you'd playing silly word games, and are going with your own definition of "password hash" that includes or excludes different hashing algorithms as it is convenient for you. I won't get drawn into that.
> What you're describing is closer to a "pepper".
What you're doing is called being "condescending." You know full well from my posts above that I am familiar with salt/peppering/hashing, and the different technologies involved. So linking to 101 tutorials and definitions of basic terms is only intended to aggravate.
I think everyone is getting a little to emotionally invested here. Might be a good time to take a step back and detach a bit. Apologies for interrupting your conversation, I just don't like seeing everyone going for each other's throats on HN.
To be honest I'd probably interpret them as being antagonistic if the same statements were directed at me (and quoting never helps either) but I think if you take a charitable interpretation it doesn't read that way. I think it's just a direct/technical challenge/debate sort of reply and it's really easy to read into those when you're on the receiving end of them.
> While some hashing libraries do insist on you supplying a salt, it is still ultimately up to the application developer to generate and store the salt for later usage.
If your password storage mechanism requires you, the programmer, to generate a salt, you may well be using the wrong password storage mechanism, or using it in the wrong way.
Using == instead of hmac.compare_digest is unlikely to be a source of vulnerabilities in your application, but it's a good habit to get into whenever you touch cryptography.
Again consider timing leaks.
Many interesting questions:
How do secrets affect timings?
How can attacker see timings?
How can attacker choose inputs to influence how secrets affect timings?
Et cetera.
The boring-crypto alternative: crypto software is built from instructions
that have no data flow from inputs to timings.
Obviously constant time.
Would it still let you sneak in if the hash was rubbish? Say it was just a simple md5 of the password. If you could do a timing attack you could use rainbow tables of the hashes and whittle down the the possible set of passwords really quickly, right?
So if the timing attack has told you that the first letter of the hashed version is 'A' then you find another password from the table that hashes to AAxxx, ABxxx, etc.
Obviously that depends on you being able to precompute all the passwords in a consistent way as the hash being used.
Along the same lines - could you use a timing attack to figure out a salt? I guess it's near impossible?
You could potentially leak the first N bytes of a valid unsalted trash hash (e.g. MD5) and then use this information to optimize an offline brute-force attack. The more bytes you leak of the hash, the more you can narrow down your offline attempts and the less subsequent packets you need to fire.
I was going to develop this into an exploit tool, called TARDIS (backronym for Timing Attack to Remotely Dispel the Illusion of Security) against, e.g. Piwik, Oxwall, and other products that still use MD5 passwords. The main reason I didn't was: No free time to build it and tune it against the internals of various programming languages' == implementations.
hmac.compare_digest is constant time whereas == will return as soon as a mismatch is found. The difference in return time can be measured. The key phrase is a Timing Attack[0].
I'm not a python person but it is probably a constant time comparison. If you compare things in such a way that the time it takes to complete increases with increasing prefix match than timing attacks are possible to recover the secret.
Is there something obvious I'm missing here?