[Bug 1703691] Re: Using iter-time doesn't give the desired timeout and security
asi
1703691 at bugs.launchpad.net
Fri Aug 18 12:34:47 UTC 2017
Volume (master) key digest is there only to verify validity of the key.
The digest iteration count is not relevant for the security of LUKS in normal situation.
This iteration (slowdown) for digest will only help if the volume key
was generated by a flawed RNG, where brute-force is possible. (For
proper RNG it is impossible to brute force key even without iterations.)
Moreover, if you know some plaintext on device, attacker will use
different trick (I think it is described in linked paper): You try to
decrypt device and check that plaintext (for example filesytem magic
string). This bypasses digest completely and cost is onle one cipher
decryption step per try (much cheaper than digest calculation).
IOW: the digest iteration count is not important, only the iteration
count in keyslot is, this one slows down password dictionary and brute-
force attacks.
--
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to cryptsetup in Ubuntu.
https://bugs.launchpad.net/bugs/1703691
Title:
Using iter-time doesn't give the desired timeout and security
Status in cryptsetup:
New
Status in cryptsetup package in Ubuntu:
Confirmed
Bug description:
I have formatted using cryptsetup with option iter-time for use longer
timeout than the default 2000ms. When I write 60000 I get 18 seconds
and 10000 is 2 seconds. Something is terrible wrong.
To get a timeout closer to what I want I wrote this script, which is
an except:
benchmarkiterations=$(cryptsetup benchmark | grep -e
'^PBKDF2-sha256' | awk '{print $2}')
cryptsetup -q --key-file ${keyfileluks} luksFormat -i $(($cryptsetuptimeout)) -c aes -s 256 -h sha256 --uuid=${uuidluks} --use-random $loopluks
timerstart=$(date +%s.%N)
cryptsetup -q --key-file ${keyfileluks} luksOpen $loopluks ${uuidluks}_${mapper}crypt
timerend=$(date +%s.%N)
cryptsetup -q luksClose ${uuidluks}_${mapper}crypt
timerdiff=$(bc -l <<< "($timerend-$timerstart)*1000")
timerfactor=$(bc -l <<< "$cryptsetuptimeout/$timerdiff")
timeoutnew=$(bc -l <<< "scale=0; ($cryptsetuptimeout*$timerfactor*1.2)/1")
cryptsetup -q --key-file ${keyfileluks} luksFormat -i $timeoutnew -c aes -s 256 -h sha256 --uuid=${uuidluks} --use-random $loopluks
iterations=$(cryptsetup luksDump $loopluks | grep -e '[[:space:]]Iterations:' | awk '{print $2}')
iterationspermsec=$(($iterations/$cryptsetuptimeout))
if [ "$iterationspermsec" -lt "500" ]; then
echo "Error too few iterations: $iterationspermsec"
exit 1
fi
First I benchmark the computer with rounds per second and then test
the desired timeout. Then I compare the benchmark with the rounds per
seconds got while testing and then calculates a new approximate value.
Then I finally format the device. This gives better values.
At lines around 700 in keymanage.c master key digest is set to the 1/8
of the expected value:
/* Compute master key digest */
iteration_time_ms /= 8;
header->mkDigestIterations = at_least((uint32_t)(*PBKDF2_per_sec/1024) * iteration_time_ms,
LUKS_MKD_ITERATIONS_MIN);
At lines around 800 in keymanage.c about half of the timeout goes
away:
/*
* Avoid floating point operation
* Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN
*/
PBKDF2_temp = (*PBKDF2_per_sec / 2) * (uint64_t)iteration_time_ms;
PBKDF2_temp /= 1024;
if (PBKDF2_temp > UINT32_MAX)
PBKDF2_temp = UINT32_MAX;
hdr->keyblock[keyIndex].passwordIterations = at_least((uint32_t)PBKDF2_temp,
LUKS_SLOT_ITERATIONS_MIN);
Moreover one second are 1000 ms, not 1024.
Benchmarking of PBKDF always gives to low speed: (from pbkdf_check.c
from line 54)
int crypt_pbkdf_check(const char *kdf, const char *hash,
const char *password, size_t password_size,
const char *salt, size_t salt_size,
uint64_t *iter_secs)
{
struct rusage rstart, rend;
int r = 0, step = 0;
long ms = 0;
char buf;
unsigned int iterations;
if (!kdf || !hash)
return -EINVAL;
iterations = 1 << 15;
while (ms < 500) {
if (getrusage(RUSAGE_SELF, &rstart) < 0)
return -EINVAL;
r = crypt_pbkdf(kdf, hash, password, password_size, salt,
salt_size, &buf, 1, iterations);
if (r < 0)
return r;
if (getrusage(RUSAGE_SELF, &rend) < 0)
return -EINVAL;
ms = time_ms(&rstart, &rend);
if (ms > 500)
break;
if (ms <= 62)
iterations <<= 4;
else if (ms <= 125)
iterations <<= 3;
else if (ms <= 250)
iterations <<= 2;
else
iterations <<= 1;
if (++step > 10 || !iterations)
return -EINVAL;
}
if (iter_secs)
*iter_secs = (iterations * 1000) / ms;
return r;
}
It is not as secure as you expect. You can decrypt the device with a
master key.
https://unix.stackexchange.com/questions/119803/how-to-decrypt-luks-
with-the-known-master-key
To manage notifications about this bug go to:
https://bugs.launchpad.net/cryptsetup/+bug/1703691/+subscriptions
More information about the foundations-bugs
mailing list