Is it safe (or optimal) to use a BCrypt hash directly as the key to an HMAC-SHA256? I ask because all the BCrypt hashes I will use contain the same salt, version, and cost, so the first 29 characters of the hashes will all look the same, e.g. "$2a$06$/H63GWnve78WGVBSDouFTO"
. I'm not comfortable with this much known structure in a key. Should I run the BCrypt hash through a SHA256 first before using it as the key to an HMAC-SHA256, or is it ok to use it as-is?
-
1$\begingroup$ It would be bad practice that "all the BCrypt hashes (…) contain the same salt, version, and cost", for that makes salt ineffective at preventing password search on several different passwords. Using the BCrypt hash as key to HMAC-SHA256 won't cure that. As pointed in this answer, HMAC-SHA256 works fine for a key of any length, and will hash it before use if too long (over 64 bytes). $\endgroup$– fgrieu ♦Aug 11 at 12:46
-
$\begingroup$ bcrypt is not a password-based KDF, just a password hashing algorithm. For key derivation, you should use Argon2. If using bcrypt for password hashing, it's best to use hmac-bcrypt as this avoids some design/implementation limitations. $\endgroup$– samuel-lucas6Aug 13 at 9:39
1 Answer
In principle HMAC can use a key fo any size. However, I'd argue that only the final 31 characters of the returned string are of importance, as that consists of the calculated bcrypt hash / the HMAC secret. Obviously you'll need to store the salt somewhere public if you want to just keep the password secret. As such it doesn't count towards the security of the resulting secret.
Now there is something of a problem: those 31 characters only represent 23 bytes of generated secret information. In principle HMAC should take a key of 32 bytes. So the output of bcrypt seems to be fall somewhat short of the recommended size for HMAC. Generally I'd say that 184 bits offer plenty of security, but switching to PBKDF2 or Argon2 could an idea.
For HMAC I say it doesn't matter much if the characters are used "directly" by interpreting them as bytes (using one specific character encoding) or if they are base 64 decoded first.
I don't see much point of hashing the output of bcrypt before putting it into HMAC. HMAC can take any size of key, and will automatically hash the input using the internal hash if it would hamper the efficiency of the algorithm.
-
$\begingroup$ Switching from BCrypt to PBKDF2 would sizably reduce the cost of password search (at equal work for key stretching by legitimate user). That's a much worse issue than the 184-bit restriction, or even the BCrypt password size limit of 72 bytes (which can be much less characters). Thus I would not recommend using PBKDF2. Switching from BCrypt to Argon2 is unlikely to harm, would raise the cost of password search (particularly when context of legitimate use allows free use of multiple processors). That's good, and has all the benefits of PBKDF2 except simplicity. $\endgroup$– fgrieu ♦Sep 10 at 7:25
-
$\begingroup$ Keeping the metadata from the hash type would be a no-effort way to provide domain-separation from other key derivation types. Since bcrypt has a fixed hash size, including the metadata would also partially fix the issue HMAC has of not discriminating between keys of different sizes that are less than the block size, where the variable bits of the key are trailing zeros. I say "partially" because there's still a possibility that a random key could incidentally contain a prefix which matches bcrypt metadata while also being of ambiguous size. $\endgroup$– aiootpSep 10 at 10:40