1
$\begingroup$

I'm creating a password vault, and I plan to use Argon2id to derive the master key from the master password. For encryption, I plan to use XChaCha20 with Poly1305.

To be clear: a set of multiple passwords and usernames will be encrypted using XChaCha20 and authenticated using Poly1305, using (a random 192-bit IV and) a 256-bit key derived from a master password using Argon2id (the version that tries to both resist GPU cracking attacks and side-channel attacks) (using 256-bit secure random salt; although I might actually use a 128-bit salt because that should also be plenty). (If there are any issues with this setup, such as using the id version of Argon2 or using XChaCha20, also tell me, but I think these should be suitable.) Eventually, I'd like to make the password vault usable on both desktop(/laptop) and mobile devices.

Now I want to determine good secure-but-not-overkill default parameters to use for Argon2id that are suited for both modern mobile phones and standard computers. The parameters to choose are the following:

  • Time cost (number of iterations)
  • Memory cost (number of KiBs to use)
  • Parallelism (number of threads to use; also influences the output)

The Argon2 draft RFC v12 tells us first to choose the maximum parallelism and memory cost you can afford and increase the time cost until the function takes longer than you can afford. (EDIT 2021: apparently, v13 now recommends parallelism of 4.)

Another page references multiple sources, such as the libsodium documentation, which has multiple recommendations:

  • "For interactive, online operations, crypto_pwhash_OPSLIMIT_INTERACTIVE and crypto_pwhash_MEMLIMIT_INTERACTIVE provide base line for these two parameters"
  • "Alternatively, crypto_pwhash_OPSLIMIT_MODERATE and crypto_pwhash_MEMLIMIT_MODERATE can be used"
    • Currently 3 iterations and 256 MiB RAM
  • "For highly sensitive data and non-interactive operations, crypto_pwhash_OPSLIMIT_SENSITIVE and crypto_pwhash_MEMLIMIT_SENSITIVE can be used"
    • Currently 4 iterations and 1 GiB RAM

(In all cases just one thread is used.)

A quick benchmark on my laptop tells me that the function just takes 3.9 seconds with the last set of parameters (using the original Argon2id implementation), which I think is more than acceptable because I prefer having a secure system. However, on my phone this takes 8 seconds (using argon2kt), which is a bit longer than I'd prefer, not to mention that 1 GiB is quite a lot of memory.

For reference I took a look at the source code of password vault KeePass, and it seems they use Argon2d (so less side-channel protection) with 2 iterations with just 1 MiB of memory (but 2 threads) by default: [excerpt from KeePassLib.Cryptography.KeyDerivation.Argon2Kdf:]

internal const ulong DefaultIterations = 2;
internal const ulong DefaultMemory = 1024 * 1024; // 1 MB
internal const uint DefaultParallelism = 2;

Is it just me, or is that a bit on the insecure side?

Also, what role does the parallelism parameter play in countering attacks? Is this not as important, as libsodium just keeps it at 1?

In conclusion, I think this is a bit vague, and I'd like to have some minimum secure values for the 3 parameters because what if I take small parameters since I have a slow phone while the attacker has a bunch of GPUs? Then my vault would be utterly useless. Also, I imagine one can go overboard and choose values way larger than necessary. Is there some limit after which directly cracking the symmetric key is faster than guessing passwords?

$\endgroup$
1
  • $\begingroup$ Minimum parameters really depends on your threat model and the machines you want to run this on. If you're actually worried about government attacks, then you need to ignore users who have slow hardware. If you want to support users with slow hardware, then you need to accept some loss in security. Unfortunately, there is no set answer for every scenario. $\endgroup$ Commented Sep 22, 2020 at 0:16

1 Answer 1

1
$\begingroup$

The parallelism was probably one reason why Argon2 won the Password Hashing Competition. The use of processor cores allows for greater memory hardness (security) without increasing the execution time accordingly. The drawback is that developers have since then been wondering what value they take for their application.

Paralellisms depends on the number of available cores. If you want your application to run on different devices, the execution time will vary greatly with higher parallelism factor. As of that time, about 50 percent have quad-core processors in their computer. This would suggest to increase the parallelism factor to 8 (twice the number of cores), but for smartphones with a single core this would roughly quadruple the execution time.

There is no clear solution for this. I personally find the choice of libsodium too extreme, even though it is most likely to be cross-device. But you are thus missing out on a major advantage of Argon2.

If you assume that the vast majority of your users have at least two processor cores, you can set the parallelism factor to 4, if you are more careful, to 2. Then you can set the assumed available memory (there is no clear solution for this too, at least 64 MiB?) and at the end set the time-factor that the execution time is maybe one second.

$\endgroup$
4
  • $\begingroup$ Thanks for your answer! At least one of my questions remains, though: is there some limit for the parameters after which directly cracking the symmetric key is faster than guessing passwords? $\endgroup$
    – SWdV
    Commented Sep 22, 2020 at 17:57
  • $\begingroup$ No, there is no such limit. Even with the lowest parameters several hash functions are executed. The cracking of the key is not relevant. $\endgroup$
    – BeloumiX
    Commented Sep 23, 2020 at 8:33
  • $\begingroup$ No I meant that maybe with very large parameters Argon2 will be so slow that bruteforcing the key is faster? (so choosing parameters that large is useless) $\endgroup$
    – SWdV
    Commented Sep 23, 2020 at 15:54
  • $\begingroup$ Cracking Argon2 is always possible for bad passwords like "123" regardless of the parameters. Bruteforcing a 256-bit-key is practically impossible. Spend your time on parameter selection, implementation errors, maybe keyloggers, but not on bruteforcing the key. That is the most secure part. $\endgroup$
    – BeloumiX
    Commented Sep 24, 2020 at 10:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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