15

I'm really trying to make sure that I follow best practices when it comes to password storage, and after some looking around for a good algorithm, I found that Argon2 was the "next big thing". I've been testing it out within VB.Net using the NuGet package provided by Liphsoft (Liphsoft.Crypto.Argon2).

By default, it looks like the parameters for the hash algorithm are stored in the hash itself. I understand (or at least I think I do) that this is suppose to make it easier to migrate it to a new hash if you ever decide to change the parameters.

My question is, does it make it less secure by supplying the hash algorithm's parameters in the hash itself? I'm currently thinking of just trimming out the information and just hiding the parameter values within code so that if someone gets a hold of the hash, they can't immediately see that "Oh, they're using Argon2 with these specific parameters." Should I even be concerned about that?

Any feedback is greatly appreciated. Thank you!

I also looked at this question before posting: Argon2 output length and parameter storage?

Nameless
  • 153
  • 1
  • 1
  • 6

2 Answers2

26

First, following the "next big thing" is not generally a good idea in the world of cryptography. You should strongly prefer battle-tested code and algorithms over new ones. In this particular case, consensus is mostly that Argon2 is highly unlikely to fall victim to attacks that make it worse in practice than scrypt, bcrypt, or PBKDF2, so you're not necessarily wrong to pick Argon2; just consider that your instincts should drive you toward more well-established, conservative choices when it comes to cryptography. You should also strongly prefer off-the-shelf algorithms and implementations over versions you've made custom modifications to; you are orders of magnitude more likely to make things weaker through a misunderstanding or a through a bug than you are to sufficiently address a real weakness. Think of it this way: if your concerns are based on something real, and they're as easy to address as you believe, cryptographers and authors of cryptographic libraries would already handle this for you.

Second, the parameters are required in order to recalculate the hash. If you specify different hardness constraints when initially hashing the password, you get out a different result. It follows that if you don't know those parameters when trying to verify the hash, you would have to try every combination of those parameters until you get lucky enough to stumble upon the result If you have these parameters stored directly in your code, you technically don't need to keep them alongside the hash itself. However, these parameters should not be set in stone: they should be continually increased as memory gets cheaper and hardware gets faster. Some libraries let you do this dynamically by "calibrating" the computation the first time you instantiate the library, such that it uses some fraction of available memory and takes (for instance) 0.1s of CPU time.

In exchange for losing this flexibility, you gain a relatively minor benefit in security. If you're using Argon2 with reasonable costs (> 0.1s), it should take an attacker an impractical amount of time to recover all but the most trivial of passwords; running through the list of the most common 1,000 passwords against a database of 10,000 users would take more than ten days of CPU-time, and even here you're better off mitigating this by preventing users from using passwords from these lists.

Still there's an undeniable, if small benefit. Can we get that benefit without the downsides? Yes. Rather than hide the cost parameters (which don't constitute much in the way of entropy), you're better off computing an HMAC of the password before sending it to Argon2. By using a secret key and computing an HMAC first, you get to keep flexibility for your cost variables, but you also prevent an attacker from having any ability to test passwords unless they've also acquired the HMAC secret, which has far more entropy than do your cost parameters.

Edit: One other thing to note is that your suggestion doesn't really defend as much as you think it would. As I point out in my comment to @LuisCabrillo's answer, the sum of these things adds up to perhaps 16 bits of entropy. Against a smart attacker who creates an account on your site with a password they already know, you've done very little to stop them now: they know the password and the matching hash, so just need to run through each possibility once until they determine your algorithm and cost factors. Then they can attack your password database per usual.

Stephen Touset
  • 11,162
  • 1
  • 39
  • 53
6

The theory of password hashing assumes that the attacker knows the function used to hash every single password entry. The function is designed to slow down an attacker who knows the parameters. So they're not required to be secret; it's perfectly fine to store them in the same output string as the hash, and the official Argon2 reference implementation outputs them the same way as well:

$ echo -n "password" | ./argon2 somesalt -t 2 -m 16 -p 4 -l 24
Type:           Argon2i
Iterations:     2
Memory:         65536 KiB
Parallelism:    4
Hash:           45d7ac72e76f242b20b77b9bf9bf9d5915894e669a24e6c6
Encoded:        $argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
0.188 seconds
Verification ok

I'm currently thinking of just trimming out the information and just hiding the parameter values within code so that if someone gets a hold of the hash, they can't immediately see that "Oh, they're using Argon2 with these specific parameters." Should I even be concerned about that?

That's a very minor security improvement; you're implicitly positing a scenario where somebody steals your password database but not your codebase, and is thus unable to use the hashes to verify their guesses. That's not an unlikely scenario for some applications (e.g., you store your password hashes in a SQL database and somebody executes an injection attack), but neither are scenarios where they steal your code (somebody uses a file access vulnerability in your web application to download its code off the server).

There's no straightforward answer here, other than perhaps this: don't make big efforts or build anything complicated to protect the secrecy of the hash parameters! Particularly more so than for the hashes or the codebase itself.

Luis Casillas
  • 14,703
  • 2
  • 33
  • 53