# Encrypting or HMACing password digests

Assuming I'm using bcrypt to digest passwords, is any additional security gained by either encrypting or HMACing the resulting digests? By requiring a key to compare password hashes, I would expect that this would prevent any attempt at brute forcing sans the key.

The keys for this operation are actually stored somewhere other than our application servers, and all cryptographic operations are performed there via API calls. The service is designed to never divulge keys themselves, and only operate on keys by an opaque ID. So it should be considered somewhat less likely that our keys would be compromised in an attack than in typical webapp scenarios. Keys are also unique per customer of our application.

I would normally only consider HMAC for this operation, but this would require extracting (and storing separately) the salt from the bcrypt digest. So simply encrypting the crypt digests seems to be the simplest approach, and intuitively should produce the same desired security properties.

Is this approach reasonable and sane? We already have the cryptography infrastructure in place, so it's not considerably more difficult to encrypt/HMAC our hashes than it is to compute them in the first place. Is there a reason to prefer an HMAC over AES-128-GCM?

-
I'd use encryption, since that allows you to upgrade hashes when you change the key. – CodesInChaos Jan 22 '13 at 19:42
That's an important feature, actually. Do you see any reason not to do either? – Stephen Touset Jan 22 '13 at 22:28
I presume from the above text that you are planning to only store the HMAC if that protocol is choosen (storing a HMAC in addition does not seem to make sense). It may be best to put the verify method in the crypto-server by the way. – Maarten Bodewes Jan 23 '14 at 15:09
Correct. That's what we did; there's simply an API call for, e.g., "generate password hash using opaque key_id" and "confirm provided password matches a given hash for some key_id". – Stephen Touset Jan 23 '14 at 18:27

If you store the encrypted digests in one location, the key in another, and send the new digest and encrypted one from the first location to the second --- you probably have much better chance to have your communications intercepted with both plaintext and ciphertext revealed compared to the chance that your encrypted database is leaked.

If you still believe that you have a secure channel and a key available, why not just apply the HMAC alone to the password||salt||ID ? The entire purpose of hashing-only passwords is to avoid messing up with secret information.

-

Either is safe, but I would prefer encryption for two reasons:

1. As noted in the comments, you can change the key without needing to know the original password.
2. Encryption doesn't add to collisions, while HMAC can. The probability is tiny, but it adds to the probability that the password hash caused a collision. Not worth worrying about, but since it's avoidable...

On the other hand, HMAC does have one advantage: no IV, so no extra space. (GCM even adds an authentication tag.) If you can use something like a user ID as a counter, even that advantage could be lost. If not, that could be important in some cases.

-

I believe you're describing a system where a client, via an API, submits the bcrypt hash of a password with a per-user salt you provide as part of a challenge. You then directly compare the presented hash against the hash you store in your database.

In that case, my recommendation would be to extract the salt, SHA-2 the hash, and then concatenate the two before storing them. HMAC would be better, but IMO, SHA-2 achieves the same goal more easily.

Using bcrypt prevents the attacker from guessing the password. But if the attacker steals your database, they don't need to guess the password. They can just present the bcrypt hash directly. But if you SHA-2 the presented hash before comparing it, then they must reverse the SHA-2 of a bcrypt hash, which is computationally infeasible. In principle, you could publish your password database without fear. (Don't do that.)

Using an HMAC with SHA-2 would also require them to have access to some static key you hold. If it's easy to implement for you, sure, why not? But I don't think it would afford you much additional security.

If you just encrypt the hashes, then you are betting that the attacker who had sufficient access to steal your database couldn't also steal some fixed key. I wouldn't bet on that. For instance, a former employee may have had access to the static encryption key (which it is unlikely you will be able to change very often if ever). They could steal the keys and database before leaving and break into accounts indefinitely without having to install a backdoor. But they couldn't reverse SHA-2, even if they stole everything. I would take the trouble to extract the salt and apply a hash (or HMAC).

-
The point of the question was to add a secret key into an otherwise-typical password hashing scheme. Simply SHA-2ing an existing password hash does not accomplish this. For posterity, what we actually went with was to HMAC the original password with the secret key and scrypt the result. – Stephen Touset Jan 22 '14 at 23:10
I don't think in general that the client should perform the "hashing". Also I'm not sure that "a former employee may have had access to the static encryption key" is sufficient reason to discard a protocol; security is normally achieved by applying different layers, and this certainly makes it harder for an attacker. – Maarten Bodewes Jan 23 '14 at 15:12
The client should definitely perform the bcrypt before sending the result to the server. That shouldn't even be controversial. The client should never send raw password if it can be avoided. I'm discussing a separate hash by the server prior to putting into the database. I believe that provides stronger protection than symmetric encryption. HMAC provides only marginally better protection than SHA for that final hash IMO. I am aware of the layers; SHA/HMAC is providing a more effective layer than symmetric encryption. – Rob Napier Jan 23 '14 at 15:28
bcrypt should likely not be performed by the client before sending to the server. The simplest reason being that client-side performance of bcrypt will likely be dramatically less than server-side performance, reducing the number of bcrypt rounds by a significant margin. Encrypting the hashes versus HMACing (either before or after) do not seem to have the different security properties you assert — if an attacker recovers the key in either scenario, the attack devolves into simply cracking bcrypt. – Stephen Touset Feb 13 '14 at 18:22

HMAC and AES-128-GCM are similar in the sens that both are symetric primitives (i.e. there are more or less the same key management issues) and both require to store extra data (salt vs. authentication tag).

An issue with encryption is that in case a poor padding scheme is used (i.e. no random) we may face to several collisions in the encrypted password table and an attacker (having the table of encrypted passwords) might perform a statical analysis to spot common passwords (e.g. 123456) and guess some of them.

-
This question is about encrypting/MACing a salted password hash. – CodesInChaos Jan 22 '14 at 13:55
Besides that, normally a two different plaintext will always result in two different ciphertexts for block ciphers modes of encryption - funny enough especially if the same IV is used. – Maarten Bodewes Jan 23 '14 at 15:01