Given an option , which one should I choose , a HMAC for storing a password securely or a bcrypt or scrypt library?
In order to give you a proper idea of the problems and subtleties of computing password hashes, as well as why HMAC isn't suitable for this problem, I'll provide a much broader answer than is really necessary to directly answer the question.
A HMAC hash algorithm is, essentially, just a keyed version of a normal hash algorithm. It is usually used to verify integrity and authenticity. The usual notation of this is
This is done as follows:
Now that you understand what HMAC is, let's move onto what you really want to do - store passwords in a database.
Many years ago, it was standard practice to store passwords in plaintext in databases. This was a bad idea because, when the database was compromised, the attacker got all the passwords. To combat this, we started hashing passwords in the database using one-way cryptographic hash algorithms. MD5 became popular, but weaknesses (collisions, partial preimage, etc) discovered in it mean it's no longer recommended. A lot of people moved onto SHA1, which is more secure.
The problem with this approach is that it's possible to construct a huge table of hashes and their corresponding plaintexts. These are called rainbow tables. They work on the concept that it is more efficient to compute a huge list of hashes for all possible passwords (within a certain set) and then store it, so it can be quickly queried later on. So, instead of brute-forcing individual hashes, it became possible to just query the database for a hash and have its plaintext returned immediately.
In order to fix this, security nerds invented salts. Salts are large unique random values appended to passwords before they are hashed. This salt is stored with the hash, so that it can be computed again later. So, we compute
So, the bad guys switched back to dictionary attacks and brute-force cracking. With the advent of GPU computing, it became possible to compute billions of hashes per second on a moderately powerful graphics card. In fact, people have built computers that can compute nearly 50 billion MD5 hashes per second - pretty impressive / scary. The reason GPUs are capable of this is that they're designed to do huge numbers of parallel scalar operations. Scalar operations are math and logic operations that do not involve branches - i.e. they don't need to do much/any "if x then do y". Cryptographic hash algorithms tend to fit into this model.
In order to make this difficult, we have to make the hash operation slow enough to make brute forcing infeasible. Normal hash algorithms (e.g. SHA1) are designed to be fast, which makes them unsuitable for this purpose. HMAC adds very little overhead and no extra security margin, so it too isn't much use here.
Creating a slow cryptographic hash algorithm is easier said than done - it's very hard to come up with one that is slow, irreducible (i.e. cannot be optimised beyond its current state) and secure. There are three popular hash functions that can do this: PBKDF2, bcrypt, and scrypt. These are known as adaptive key derivation functions, because they accept a work factor value along with the plaintext and salt. The work factor alters the amount of time it takes to compute the hash, and is designed to safeguard against future hardware improvements.
So, for an adaptive key derivation algorithm
In order to provide more security against dedicated hardware-based cracking, scrypt ensures that the hash computation is both CPU-hard and memory-hard, i.e. it requires significant CPU and memory resources in order to produce the hash value. This is important, because FPGAs usually have access to very little immediate memory.
Now, the obvious question arises: if I set up my site to use bcrypt, won't that mean my server has to compute CPU-intensive hashes all the time? Well, if you run them on your server, then yes, that's something to take into consideration.
Hopefully this gives you a good overview of the situation, and why HMAC isn't suitable for this kind of use.
|show 2 more comments|
HMAC is designed to be very fast and is in this context a good way to add salt to password instead of just appending it. Bcrypt is much slower due to slow initialization, while scrypt is even slower than Bcrypt because it is intentionally designed in such a way. Scrypt is designed to make brute forcing it very computationally expensive. It consumes a lot of CPU, memory and is also slow to use on GPUs.
Although nominally for integrity checks, it so happens that HMAC (when used with a reasonably secure hash function, e.g. SHA-256 or even SHA-1) behaves somehow like "a hash function with a key". This is not a generic property of MAC algorithms, but it works with HMAC (that's why it can be used as basis for a random generator called Hmac_DRBG). This makes HMAC a potential choice for password hashing.
If you "hash" your password with HMAC, and the attacker could grab your file/database of hashed password but not the HMAC key, then the attacker will not be able to crack the passwords. In that scenario, HMAC is "better" than bcrypt/scrypt. However, this is an edge case. We hash passwords because we worry about fringe scenarios where the attacker could breach security enough to get a read-only access to part of the server files, but not a read-write access. Th e hash-with-HMAC method is for a fringe-squared scenario where the read-only attacker could get the hashed password but not the key, which is nonetheless stored on the same server.
If the attacker could get the key, then HMAC becomes only a simple hash function for him, and in that case HMAC is much worse than bcrypt, because it is unsalted and too damn fast. It is like if the passwords where hashed with a pair of SHA-1 invocations. That scenario is no less probable than the previous, and thus we must consider use of HMAC alone as too risky.
For the best of both worlds, apply HMAC on the user password, and then process the HMAC output through bcrypt; you will store the output of bcrypt. Since bcrypt implementations expect the password as a character string, you would have to encode the HMAC output (hexadecimal, Base64...).
This is more complex than bcrypt alone, because of using two functions instead of one, and because of the key (which brings the whole thorny issue of key management: generation, storage, backup...). Since complexity is bad, I would recommend against it; simply use bcrypt alone, and don't add an HMAC. However, this is your call; if you really want the HMAC, use it in addition to bcrypt, not instead of bcrypt.
(Note: that's bcrypt on the HMAC output, not the other way round, which would not work because of the salt which is included in the bcrypt output.)