10
$\begingroup$

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?

$\endgroup$
24
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ I couldn't help but to read this in the voice of Neil deGrasse Tyson, as it was explained very well! I can see that storing the parameters may be particularly useful for migrating the hashes to increase the costs later on, all without having to create new database fields and more complex code to handle it. I do like how you mentioned the fact that it is new and not battle-tested like some of the other well-known algorithms, so I may end up considering bcrypt or the .Net implementation of PBKDF2 (Rfc2898DeriveBytes) until Argon2 becomes more proven. Thank you so much for the response! $\endgroup$ – Nameless Feb 2 '17 at 19:30
6
$\begingroup$

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.

$\endgroup$
  • 1
    $\begingroup$ Also, even if they get the password database without the parameters, there's not much entropy there; parallelism is overwhelmingly like to be 1-8, iterations 1-8, and memory a power of two between 1-128 MiB. Even being generous, this is less than 16 bits of entropy $\endgroup$ – Stephen Touset Feb 1 '17 at 19:19
  • $\begingroup$ @StephenTouset: Or the hash might be PBKDF2 with one of a few HMAC instances and 1,000-100,000 iterations, bcrypt with a handful work factors, scrypt with various parameters, or (more likely?) just homebrew salted SHA-1 with god knows what silliness thrown in. And your "less than 16 bits of entropy" is similar to the stretch introduced by 50,000 iterations of PKBDKF2—not too shabby. I certainly think it's not worth any extraordinary effort to hide the algorithm and parameters—not a great use of one's time—but I can also picture an attacker being seriously inconvenienced by it. $\endgroup$ – Luis Casillas Feb 1 '17 at 20:30
  • $\begingroup$ My point is closer to what's echoed in my own answer: if you're going to go through this trouble, why not just use an HMAC and get 256 bits of entropy without any of the downsides? $\endgroup$ – Stephen Touset Feb 1 '17 at 21:11
  • 1
    $\begingroup$ That's not the same, though. If you strip off the security parameters because they're hardcoded elsewhere, you're forcing the attacker to perform extra iterations, even though you aren't. Also one thing that's important to note is that the extra entropy added through hiding these parameters is only necessarily to determine once. An attacker may not know which algorithm and what parameters you used, but if they have an account they already know the password for, they can just use that to determine the hardcoded values for all entries in the database! $\endgroup$ – Stephen Touset Feb 1 '17 at 21:54
  • 1
    $\begingroup$ That's all true, but my point really is that if somebody's worried that the attacker gains an advantage from knowing what algorithm and parameters they're using, they should really consider just increasing the work factor. It's not about whether it's strictly equivalent, it's about whether it's a more sensible alternative. $\endgroup$ – Luis Casillas Feb 1 '17 at 22:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.