2

The luksFormat command accepts iteration time as a parameter, not iterations. That obviously leads to quite different number of iterations depending on the hardware doing the encryption. However if I am protecting the same data on systems of vastly different performance, the security is as weak as the slowest machine. So I am curious, how many iterations (not iteration time) would be considered secure so I know what to aim for?

5
  • If we know the strength of your password and the key derivation function that you are going to use on the luks, then we can talk about numbers. Currently, it is ambiguous! In addition, who is that you are you protecting your data?
    – kelalaka
    Sep 24, 2023 at 21:21
  • How would number of iterations be better? Iteration time allows you to know the desired duration exactly. Where as if you use the number of iterations, you don't know the duration - is it 0.001s, 0.01s, 0.1s or 1s.
    – mentallurg
    Sep 24, 2023 at 22:17
  • But with the iteration time, you also do not know the duration. Ignoring how slow Grub is when unlocking, the attacker can very well have stronger hardware then you. In that case you are back to not knowing the duration, no? So good enough iteration count sounds like better approach...
    – graywolf
    Sep 25, 2023 at 15:30
  • Key derivation is PBKDF2, strength of password I am not sure how to measure... Almost 30 characters? :)
    – graywolf
    Sep 25, 2023 at 15:31
  • PBKDF2 is only using iteration count so, it is easy to measure that to convert into seconds, on the otherhand, if you use dicewire of bip-39 like passwords, we can talk about the strength then we can adjust it according to your security reqirements.
    – kelalaka
    Sep 25, 2023 at 21:48

2 Answers 2

0

I dont think there will ever be a right answer to this. You will need to make a decision based our own understanding of the adversary and what you are trying to protect

0

So let's play around a little with this!

I'll use a little 120GB USB3.0 drive (henceforth known as /dev/sdd) for use with luksFormat; it may not translate 1:1 for the use on your disks (and certainly not to your system resources), but it'll give us an idea of iterations used on a fairly aged CPU.

Because, as your question poses, --iter-time is focused on the time duration in milliseconds for which to run a PBKDF and not the number of iterations itself, you may not necessarily know how many iterations upon creation of the KDF will occur. We can run a loop of luksFormat with a mild password to get an idea for a different durations of --iter-time on the same processor to see some level of variation:

NOTE: I'm echoing a password into cryptsetup for the purposes of a little test, please don't do this. Additionally this will warn you of an existing LUKS superblock: worth ignoring for this test (and is ignored in the output), but ideally you'd want to give a full wipe to the device before creating a new LUKS partition.

for i in {1..6}; do
    echo -n "m1ldlyOKp4ssw0rd?!" | \
    sudo cryptsetup luksFormat /dev/sdd --iter-time 3600 -
    sudo cryptsetup luksDump /dev/sdd | grep -E "Time cost:|Iterations:"
done

Output:

    Time cost: 14
    Iterations: 93090
    Time cost: 14
    Iterations: 92174
    Time cost: 14
    Iterations: 92958
    Time cost: 14
    Iterations: 93356
    Time cost: 14
    Iterations: 93756
    Time cost: 14
    Iterations: 93090

Let's see what this looks like in varying multiples of 3600:

for i in {1..6}; do
    echo -n "m1ldlyOKp4ssw0rd?!" | \
    sudo cryptsetup luksFormat /dev/sdd --iter-time $(( $i * 3600 )) -
    sudo cryptsetup luksDump /dev/sdd | grep -E "Time cost:|Iterations:"
done

Output:

    Time cost: 14
    Iterations: 92958
    Time cost: 30
    Iterations: 93489
    Time cost: 45
    Iterations: 93756
    Time cost: 61
    Iterations: 93356
    Time cost: 76
    Iterations: 93090
    Time cost: 91
    Iterations: 92958

What gives? Why with increased values of --iter-time do we not really see much in the way of a change in iterations?

As you can see, time cost is what increases significantly and not the number of iterations - increasing the amount of passphase processing.

With my current setup using [email protected], the default PBKDF function used is argon2id and this may involve cryptsetup automatically performing system benchmarking for the base minimum of the minimum memory size (m), the minimum number of iterations (t), and the degree of parallelism (p) (all of which can be manually set) - which may normalize the results of the number of iterations regardless of --iter-time.

While I don't have a figure to point to specifically at this moment, argon2id requires significantly less iterations (I've seen ballparks ranging from 1:10000 to 1:800000) in terms of compute cost equivalence to standard PBKDF2. Argon2 is very expensive due to parallel computation with a high memory need, and thus is highly resistant to attack.

Alright, so what now? Going back to one of your statements:

"the security is as weak as the slowest machine"

In a sense, but not fully. Given the nature of development of PBKDF functions - you can have a weak computer but using an efficient KDF significantly reduces the likelihood of an attacker succesfully guessing your key. I like how Neil Madden on their blog post On PBKDF2 Iterations said:

"..there is no sane parameters for password hashing that provide anything like the security levels expected in modern cryptography. A lot of the discourse around password hashing gives the impression that there is some magic number you can pick that actually makes passwords safe to use for this kind of thing. There isn’t.""

And they go on to add:

"All this is to say that the point of password hashing is not to prevent brute force attacks. It is instead to buy some time. By slowing down an attacker you hope that you will have enough time to (1) notice you’ve been breached, and (2) change your passwords. That’s all a password hash can ever do. If you are storing user password hashes on a server then this is crucial and you should definitely use as many iterations as your hardware can cope with"

So that is to say that as @CarriMegrabyan said there may never be [an exact] right answer to this, because the point is simply to reduce the effectiveness of an attacker. Surely, if you set your iterations low with a weak KDF you're going to be susceptible to an inexperienced adversary with just enough compute at their disposal.

Seeing as the number of iterations recommended by OWASP for key derived functions rises every few years (depending on the exact KDF) this simply means an increased imperative to keep up with the attack landscape which includes increased access to higher levels of compute year over year.

And based on the cryptsetup-luksFormat manpage there exists the ability to set PBKDF iterations, but this is (to me) actually a very misleading name for the flag as it directly sets the time-cost (in seconds) and not the iterations for the PBKDF while skipping the system benchmarking the PBKDF (additionally settings for threads and memory cost can be set with this flag).

Using that setting without additional arguments we get a lower iteration count, but a higher time cost:

echo -n "m1ldlyOKp4ssw0rd?!" | \
sudo cryptsetup luksFormat /dev/sdd --pbkdf-force-iterations 120 -
sudo cryptsetup luksDump /dev/sdd | grep -E "Time cost:|Iterations:"

Output:

    Time cost: 120
    Iterations: 1000

There won't be a magic value of iterations because that depends on many factors. What matters most is balancing the time cost to your systems for the creation of the key with the time cost to potential attackers.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .