For years our assessments have discovered insecure mechanisms for password storage. Though well-intentioned developers often put a good deal of thought into schemes they seldom resist attack. Not surprising–applying the appropriate cryptographic primitives effectively proves challenging for many security practitioners. Available material, such as the simple OWASP Cheat Sheet and more thorough Threat Model, help educate but questions remain in readers’ minds. Over the last three years I continue to be asked:
“Are the SHA2 family of functions ‘more secure’ than SHA1?”
“Can I use a SHA256 or SHA512 to securely store passwords?”
To answer these high-level questions, we need to get more specific about what was meant.
The SHA2 family of functions serve the same end as SHA1: provide a collision-resistant cryptographic hash of given input as fixed-length output. The NSA designed SHA2 to overcome theoretical breaks in SHA1. The new design improved security by increasing collision resistance. An attacker requires more time to find any two messages m1 and m2 that hash to that same value ‘h’. So, yes, in terms of collision resistance, we believe the SHA2 family more secure than SHA1. In terms of passwords: it should take an attacker longer to find two unique passwords the authentication routine will verify. Unfortunately, the two most straightforward classes (brute force and dictionary-based attack) do not seek collisions to authenticate attackers. Instead, an attacker tries potential passwords, hashing them with the chosen algorithm, until discovering the password corresponding to the stolen hash.
So, in short: “No, SHA2 doesn’t improve password security over SHA1. Do not use only SHA2 to protect passwords. Ever.”
Increased resistance to collision means SHA256 and SHA512 produce longer outputs (256b and 512b respectively) than SHA1 (160b). Those defending use of SHA2 cite this increased output size as reason behind attack resistance. Some go further, backing their conclusion by asserting that brute forcing SHA512 takes 2^512, whereas SHA1 takes 2^160. They’ve reached a faulty conclusion. The irreversible property of hashes prescribes finding a password from its hash using dictionary-based or brute force attacks from input to output by executing the hash until successful. A third property (hashes are super fast) makes this approach attractive.
Because an attack iterates through the input space the size of a password cracking dictionary (say 300-400,000 very common passwords) confines dictionary-based attacks, while password length and strength requirements confine brute force attacks. Note the loop guard below:
verify = hashing_scheme.hash for password_candidate in dictionary: if (verify(password_candidate) == password_hash): return password_candidate
When attacking a population of passwords protected by SHA2, 400,000 tries represents trivial effort.
Two schemes address this problem: adaptive one-way functions slow down each attempted verify by iterating internal operations and HMAC functions add secret key to the input space an attacker must brute force, thus pushing it beyond feasibility. Though not the purpose of this entry, prepending a salt to the password prior to applying protection disambiguates two identical protected passwords. See OWASP Cheat Sheet and more thorough Threat Model for Secure Password Storage for more detail.