[dm-crypt] [PATCH] Speed up keyfile reading

angelomariafederichini191269 angelomariafederichini191269 at protonmail.com
Sat Aug 12 20:26:19 CEST 2017


Hi

(Sorry if this mailing list isn't the right place for patches but I
couldn't find any instructions on how to contribute. Maybe that's worth
a FAQ entry by its own.)

I'm using a keyfile instead of a passphrase for my encrypted volumes.
What me bothered a long time is that it takes nearly 30 seconds to open
the volume. Now I had a little time and dug into this itch.

I discovered that the crypt_keyfile_read() function in lib/utils_crypt.c
reads the keyfile one byte at a time "read(fd, &pass[i], 1)".

Attached you find a patch which enhances the loop to use bulk read
operations instead of single byte ones. To set char_to_read to the
minimum of two values I currently use the ternary operator :? because C
does not offer a standard function for this simple job. Usually one
would define an separate helper function, but I wanted to keep the patch
small&simple and also did not know if that's the "style" of cryptsetup
or if a preprocessor definition would be more appreciated.

Another note about the implementation: If we scan for an EOL then we
fall back to reading one char at a time. This way we ensure backwards
compatibility and do not read more than necessary from the file
description.

Anyway, in my test scenario this patch reduces the opening time from
25-26 seconds to 14-15 seconds. A 10 seconds improvement yeah!
(I did a very simple measurement: "time cryptsetup open ..." where the
keyfile as well as the volume file resided on a tmpfs in memory.)

I also attached a second patch which sets the initial buffer size to the
requested keyfile_size. This prevents increasing the buffer in 4k steps
over and over again if the keyfile_size is known in advance (i.e. if the
parameter 'keyfile_size_max' is set to something non-zero).

With this patch (and passing --keyfile-size parameter) opening a volume
now takes 5 seconds. Again a 10 seconds improvement. I split this into a
separate patch because I'm unsure if it is intended to update the buffer
in 4k steps as the comment "/* use 4k for buffer (page divisor but avoid
huge pages) */" suggests.

Below is the "test case code" (I wouldn't call it code). It is not a patch
because I did not understand the test suite. So someone with more knowledge
might want to convert these into more suitable test cases. The tests also need
manual supervision (looking at the output to decide if the test succeeded).

Kind regards

#!/bin/sh
set -e # abort on error

truncate -s 100M test_volume.vol
cryptsetup luksFormat test_volume.vol
# Password: "somesome"

printf "1: should fail since 'somesomething' is consumed completely \n"
#printf "somesomething\n"   | (cryptsetup open test_volume.vol test_volume; cat)
#cryptsetup close test_volume
printf "2: should succeed and print 'thing' (which is not consumed by cryptsetup)\n"
printf "somesome\nthing\n" | (cryptsetup open test_volume.vol test_volume; cat)
cryptsetup close test_volume
printf "3: should fail since 'somesomething\\n' is consumed completely\n"
#printf "somesomething\n"   | (cryptsetup --key-file - open test_volume.vol test_volume; cat)
#cryptsetup close test_volume
printf "4: should fail since 'somesome\\nthing\\n' is consumed completely\n"
#printf "somesome\nthing\n" | (cryptsetup --key-file - open test_volume.vol test_volume; cat)
#cryptsetup close test_volume
printf "5: should fail\n"
mkfifo key.fifo
printf "somesome\nthing\n" > key.fifo &
# should fail
#cryptsetup --key-file key.fifo open test_volume.vol test_volume
#cryptsetup close test_volume
printf "END\n" > key.fifo & # make sure some data is in the fifo otherwise the following cat will block
cat key.fifo
rm key.fifo

printf "6: should succeed due to --keyfile-size passed correctly\n"
printf "somesomething\n"   | (cryptsetup --keyfile-size 8 open test_volume.vol test_volume; cat)
cryptsetup close test_volume
printf "7: should succeed due to --keyfile-size passed correctly\n"
printf "somesome\nthing\n" | (cryptsetup --keyfile-size 8 open test_volume.vol test_volume; cat)
cryptsetup close test_volume
printf "8: should succeed due to --keyfile-size passed correctly\n"
printf "somesomething\n"   | (cryptsetup --keyfile-size 8 --key-file - open test_volume.vol test_volume; cat)
cryptsetup close test_volume
printf "9: should succeed due to --keyfile-size passed correctly\n"
printf "somesome\nthing\n" | (cryptsetup --keyfile-size 8 --key-file - open test_volume.vol test_volume; cat)
cryptsetup close test_volume

printf "10: should succeed\n"
mkfifo key.fifo
printf "somesome\nthing\n" > key.fifo &
cryptsetup --keyfile-size 8 --key-file key.fifo open test_volume.vol test_volume
cryptsetup close test_volume
printf "END\n" > key.fifo & # make sure some data is in the fifo otherwise the following cat will block
cat key.fifo
rm key.fifo
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.saout.de/pipermail/dm-crypt/attachments/20170812/04c5b6a6/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Use-bulk-read-when-reading-keyfile.patch
Type: text/x-patch
Size: 2442 bytes
Desc: not available
URL: <http://www.saout.de/pipermail/dm-crypt/attachments/20170812/04c5b6a6/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-Allocate-suitable-sized-buffer-when-reading-a-keyfil.patch
Type: text/x-patch
Size: 1183 bytes
Desc: not available
URL: <http://www.saout.de/pipermail/dm-crypt/attachments/20170812/04c5b6a6/attachment-0001.bin>


More information about the dm-crypt mailing list