Basic Assumptions
Let us assume I work for a company, which aims to authenticate users using traditional usernames and passwords. The company currently uses a slow key-derivation function to hash passwords, such as Argon2, scrypt or PBKDF2.
It is further assumed that a network HSM can calculate the HMAC of a string with a stored key, but cannot calculate a KDF on its own.
The Idea
One of the developers now had an idea of using a Hardware Security Module to further secure the credentials. He had the idea to use the HMAC of the password as the input for the key derivation function. Since the actual key for the HMAC function is stored inside the HSM and can't be extracted. So here in pseudo-code is once the old login code, and the new login code:
// Old Login Code
function Authenticate(input)
{
user = DB.getUser(input.username);
if (user == null) return false; //User does not exist
kdf = Argon2id;
return kdf.verify(user.password, input.password);
}
And here is the new login code:
// New Login Code
function Authenticate(input)
{
user = DB.getUser(input.username);
if (user == null) return false; //User does not exist
kdf = Argon2id;
keyedHash = HSM.getHMAC(input.password, useInternalKey=true);
return kdf.verify(user.password, keyedHash);
}
My Reasoning
This seems to overall improve the security, because an attacker who is able to steal the database, would also need access to the HSM to attempt to crack the keys. Even if an attacker knows their own password, the key stored inside the HSM is sufficiently long that attempting to brute-force the key would not be feasible.
While an attacker with control over the database might be able to send password candidates to the HSM to get the keyed hashes in return, it will:
- severely limit the amount of candidates the attacker can attempt per second
- likely cause the network administrators to see unusual network traffic and detect the breach
Possible Downsides
I am aware of "Never Roll Your Own!", and I believe that this is not "my own algorithm".
Furthermore, I understand that, should the HSM ever lose the key, users would now not be able to log in anymore. This problem could be solved with using a backup HSM and storing the key there as well.
My question
Does this scheme make any sense? Does it actually prevent an attacker from being able to recover passwords? Or is it just an excuse for the IT team to spend lots of money to get a shiny new thing?