First, make sure you read this answer to the question "Client side password hashing", paying particular attention to the last paragraph.
That said, if you want to give the user peace of mind, that's fine; do the following:
- Client side PBKDF2 hashing for a known, "high" iteration count.
- Double bonus points if the user is allowed to select the iteration count themselves!
- A good hash of the username and password as a salt isn't great, though it's better if your code pads the username out to the maximum possible length and puts it first.
- That way, "user1" and "password" don't make the same salt as "user" and "1password"!
- There is, of course, no maximum length on the password except what's caused by your back end software; SQL Server, for instance, has an 8000 byte maximum on "less inefficient" string work.
- Send that hash by itself to the server
- which then DOES generate a cryptographically random salt of 12-16 bytes
- and then uses PBKDF2 with a much higher iteration count to hash the hash passed in
- again hopefully HMAC-SHA-512 for the 64 bit operations to lessen the proportionate advantage of offline GPU attacks.
- because then someone who gets your leaked password database still has to do the work of an attack against a password hashing function to log in, rather than simply sending the client-generated hash they stole and having it be accepted as-is.
Remember with PBKDF2 password hashing in particular, never ask for an output size larger than the native base hash's output size. Smaller is all right if you're really, really concerned about storage; for instance, requesting only 32 bytes of PBKDF2-HMAC-SHA-512's native 64 byte output.
- 20 bytes for SHA-1
- 32 bytes for SHA-256
- 64 bytes for SHA-512