In this article, I share performance results of cryptographic integrity checkers for full-disk encryption in Linux. Specifically, integrity checkers implemented by dm-crypt/dm-integrity. Integrity checking may be combined with encryption into one algorithm called “authenticated encryption”; these are measured too.
The AES cipher in the GCM mode and the ChaCha20 cipher with the Poly1305 authenticator are not measured. As Broz, Patocka, and Matyas and
this talk point out, the implementation of GCM in the Linux kernel is not usable because its nonces are short, and ChaCha20 has the same problem.
The underlying device is tmpfs, in other words, RAM. Hence the implementations of cryptographic algorithms are not constrained by a device; I do not intend to measure SSD performance.
The file /tmp/benchmark that is read and written by benchmarks is prepared with
dd bs=1048576 count=64 if=/dev/zero of=/tmp/benchmark
dd ensures that /tmp/benchmark is not a sparse file. A key for encryption and integrity checking is produced with
dd bs=64 count=1 if=/dev/urandom of=/tmp/key
For I/O benchmarking, I use fio. Since I do not measure file system, cache, or SSD performance, only the throughput of sequential reading and sequential writing is measured. The benchmark commands BENCHMARK_COMMANDS are
fio --rw write --filename $BLOCK_DEVICE a.fio
fio --rw read --filename $BLOCK_DEVICE a.fio
where a.fio contains
[global]
bs=1M
iodepth=64
ioengine=libaio
gtod_reduce=1
numjobs=4
group_reporting=1
time_based
runtime=10
[job]
BLOCK_DEVICE is /tmp/benchmark when the raw performance is measured and /dev/mapper/benchmark when the performance of integrity checking or encryption is measured.
In measurement results, an encryption/authentication mode is labeled by a string of the form "$ENCRYPTION/$INTEGRITY/$JOURNALING". For example, the performance results of the AES cipher in the XTS mode and integrity checking with HMAC with SHA1 and journaling on are shown under the label “aes-xts-plain64/hmac-sha1/yes”. Below are specific commands for measuring performance in every mode. The raw mode shows a level at which RAM and CPU begin to constrain the performance.
mode: //
$BENCHMARK_COMMANDS
mode: cipher_null//
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher cipher_null --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: /crc32c/no
integritysetup --sector-size 4096 --integrity crc32c --integrity-no-journal format /tmp/benchmark
integritysetup --integrity crc32c --integrity-no-journal open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
integritysetup close benchmark
mode: /hmac-sha1/no
integritysetup --sector-size 4096 --integrity-key-file /tmp/key --integrity-key-size 20 --integrity hmac-sha1 --integrity-no-journal format /tmp/benchmark
integritysetup --integrity-key-file /tmp/key --integrity-key-size 20 --integrity hmac-sha1 --integrity-no-journal open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
integritysetup close benchmark
mode: aes-xts-plain64//
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher aes-xts-plain64 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: aes-xts-plain64/hmac-sha1/no
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher aes-xts-plain64 --integrity hmac-sha1 --integrity-no-journal --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key --integrity-no-journal open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: aegis128-random/aead/no
cryptsetup --type luks2 --cipher aegis128-random --key-size 128 --integrity aead --sector-size 4096 --key-file /tmp/key --integrity-no-journal --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key --integrity-no-journal open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: /crc32c/yes
integritysetup --sector-size 4096 --integrity crc32c format /tmp/benchmark
integritysetup --integrity crc32c open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
integritysetup close benchmark
mode: /hmac-sha1/yes
integritysetup --sector-size 4096 --integrity-key-file /tmp/key --integrity-key-size 20 --integrity hmac-sha1 format /tmp/benchmark
integritysetup --integrity-key-file /tmp/key --integrity-key-size 20 --integrity hmac-sha1 open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
integritysetup close benchmark
mode: aes-xts-plain64/hmac-sha1/yes
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher aes-xts-plain64 --integrity hmac-sha1 --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: aegis128-random/aead/yes
cryptsetup --type luks2 --cipher aegis128-random --key-size 128 --integrity aead --sector-size 4096 --key-file /tmp/key --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: /hmac-sha256/yes
integritysetup --sector-size 4096 --integrity-key-file /tmp/key --integrity-key-size 64 --integrity hmac-sha256 format /tmp/benchmark
integritysetup --integrity-key-file /tmp/key --integrity-key-size 64 --integrity hmac-sha256 open /tmp/benchmark benchmark
integritysetup close benchmark
mode: /hmac-sha256/no
integritysetup --sector-size 4096 --integrity-key-file /tmp/key --integrity-key-size 64 --integrity hmac-sha256 --integrity-no-journal format /tmp/benchmark
integritysetup --integrity-key-file /tmp/key --integrity-key-size 64 --integrity hmac-sha256 --integrity-no-journal open /tmp/benchmark benchmark
mode: aes-xts-plain64/hmac-sha256/yes
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher aes-xts-plain64 --integrity hmac-sha256 --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
mode: aes-xts-plain64/hmac-sha256/no
cryptsetup --type luks2 --sector-size 4096 --key-file /tmp/key --cipher aes-xts-plain64 --integrity hmac-sha256 --integrity-no-journal --iter-time 100 luksFormat /tmp/benchmark
cryptsetup --integrity-no-journal --key-file /tmp/key open /tmp/benchmark benchmark
$BENCHMARK_COMMANDS
cryptsetup close benchmark
Results in CSV:
encryption/integrity/journal,"Sequential reading, MiB/s","Sequential writing, MiB/s"
//,12567.06,4934.57
cipher_null//,7236.37,2762.62
/crc32c/no,7156.80,3055.56
/crc32c/yes,7182.00,533.24
aegis128-random/aead/no,6206.72,906.96
aegis128-random/aead/yes,6213.68,906.91
aes-xts-plain64//,5296.00,2379.60
/hmac-sha1/no,3175.20,1971.55
/hmac-sha1/yes,3200.40,1140.30
aes-xts-plain64/hmac-sha1/no,1974.03,1903.11
aes-xts-plain64/hmac-sha1/yes,2030.40,1722.06
/hmac-sha256/no,1486.8,1190.62
/hmac-sha256/yes,1561.5,686.7
aes-xts-plain64/hmac-sha256/no,883.6,1527.36
aes-xts-plain64/hmac-sha256/yes,996.4,1451.72
and
ODS with a
cute performance graph.
I can't declare a winner since the results are inconclusive and weird. The main issue is that writing with AEGIS-128 is considerably slower than writing with AES-XTS and SHA-1 while their relationship for reading is reverse. Reading with AEGIS-128 is 7 times faster than writing. This seems wrong. If it is correct, considering that NVMe SSDs in the price range from 100 to 150 USD offer a throughput at about 3 GiB/s, the throughput of a cipher at 1 GiB/s is disappointing. The writing performance of CRC32C with journaling is clearly wrong too. The writing performance of HMAC with AES-XTS is greater than HMAC without encryption while it should be the reverse. Maybe, I set up dm-crypt/dm-integrity wrong? Can anybody replicate my results?
System configuration is below.
CPU: AMD Ryzen 3 2200G
RAM: 2×8GB, DDR4, 3200 MHz, G.Skill Ripjaws V, Black, F4-3200C16D-16GVKB, 16-18-18-38
motherboard: MSI B450-A Pro
uname -r
5.11.2-arch1-1
pacman -Q fio
fio 3.25-1
mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,size=7154472k,nr_inodes=409600,inode64)
Works Cited
Broz, Milan, Mikulas Patocka, and Vashek Matyas. “Practical Cryptographic Data Integrity Protection with Full Disk Encryption Extended Version.” arXiv e-prints (2018): arXiv-1807.