First, don't use bcrypt
. Use PBKDF2 instead. This will allow you to increase the difficulty of doing an offline brute force attack. [Not saying that bcrypt won't, they are essentially the same, but PBKDF2 supports any hashing function, not just Blowfish]
Second, here is how you should do this.
- Randomly Generate (don't base it on anything) a 128-bit random number for the Salt
- Store the Salt as it's own parameter in the database. Remember the purpose of the salt is to make it so that the same password hashed twice doesn't have the same result.
- Pick a good Hashing Algorithm. My recommendation, use SHA-256 or SHA-512. This is what you will use as part of the
PBKDF2
function.
- Do some research, figure out what is a good number of rounds to make the hashing of the password take 1 second. Remember if we have a password keyspace of 96 characters and a minimum of 8 characters wide, and each permutation takes a required 1 second to calculate, then an attacker will cry. The nice part of this is that over time as computers become faster, you can reevaluate this value and hash the hash a few more times to bring it up to the new 1 second requirement. Example: Say that 12 rounds of SHA-256 takes 1 second on modern computers. In 5 years, the computers are now so fast that 12 rounds takes 20ms instead. But 16 rounds takes 1 second on the hardware then. Just hashing the hash 4 additional times now keeps it at 1 second. The user never knew this happened because you didn't have to ask them to change their password.
- You could store your password in the Shadow format, sure, but if you are using a database, just use database fields. You parsing a string is slower than the database just knowing what to give you.
Now I want to point out a timing attack in your system. If you tell an attacker that a username doesn't exist or the amount of time it takes to return an error is different (and shorter) than it takes to return a success, then you have a possibility for a side channel attack. Additional information can make it easier for an attacker to enumerate user accounts on your system (and if the username is based on Email, then they can now do a phishing attack against the user directly).