I learned that the Sun guys used the login name as salt for password hashing. Is this a common approach? What are the most common salt values?
Using the login name as salt is common but not really recommended: it does only part of the job. The point of a salt is to be as unique as possible among all instances of hashed passwords, so as to thwart any attempt as parallel attacks (attacking several hashed passwords simultaneously, using precomputed tables such as rainbow tables... are parallel attacks). On distinct systems, several users may share the same login name (there are so many Jones and Smiths out there). Also, a given user may change his password while keeping his name; but even an old password is valuable for an attacker (if only because an old password is often a password that the user will reuse the next time he is being instructed to change his password; also, many users will use identical passwords on other systems).
The recommended way to generate a salt is to use a good random number generator (ideally cryptographically strong RNG) and have it produce a bunch of random bytes. If the salt is long enough (16 bytes or more) then this ensure the required uniqueness with overwhelming probability, and without much hassle (no need to lookup in a database of existing salts, for instance).
We can only hope that this recommended way is also, or will soon become, the "most common" way.
The following is a decent system for salting and hashing passwords. There are a number of points to keep in mind, which is why it looks long. This is a typical example of what one should do when it comes to salt-hashing; I am not going to address what Sun does.
Salts and passwords are best dealt with as raw bytes (
Let's generate a new salt using a cryptographically strong pseudo-random number generator to generate the salt. In Ruby, that library is conveniently called
Let's use SHA256 as our underlying hash algorithm. All hash algorithms have an output size, which is the size in bits of the output of the hash function. All hash algorithms also have a characteristic internal block size, which is not the same as the output size. Let's use a salt as large as the hash algorithm's block size. We do this because this is the largest amount of entropy we can add to the password before hashing it. If we use a larger salt than the block size of the underlying hash algorithm, then HMAC will simply hash the salt first to obtain a smaller salt, reducing its entropy, before mixing it with the password. The block size of SHA256 is 512 bits (= 64 bytes), so let's use a 64-byte salt.
Let's use HMAC-SHA256 instead of SHA256 directly, which does a little bit more work to keep the password safe. We will use the salt as the key parameter to HMAC-SHA256 instead of prepending it to the password. HMAC-SHA256 wraps up SHA256 and does a little extra work to merge the salt with the password.
Finally, the hash algorithms such as SHA-256 are designed to be fast. Whatever our code does overall, it's likely to be spending 1% of its time authenticating users and 99% other stuff. If an attacker gets a copy of the password file, his code is likely to be spending 100% of its time brute-forcing the passwords. So let's make the overall algorithm super-slow: not too slow that it impinges on the rest of our code, but slow enough to discourage the attacker. Let's take a parameter called the work factor (which might be 16), and iterate HMAC-SHA256 2 ^ work-factor times (65536 times in the example). If the work factor were 2, then that would look like
A good yet simple solution in Ruby:
|show 6 more comments|