dm-crypt benchmarks

While setting up encrypted swap on yet another Linux machine, I wondered what the "best" crypto algorithm would be.

There are plenty of combinations of ciphers, modes, hash algorithms and keysizes to chose from with cryptsetup(8), let's see if we can find a fast, yet sufficiently "secure" one.

Before testing these combinations I wanted to find out which combinations were actually possible. E.g. setting up a dm-crypt device with aes-cbc-plain with a keysize of 128 or 256 bit would be possible - but any larger keysize was rejected. There were many "invalid" combinations, for reasons rooted deeply in their mathematical properties. So, let's find out these valid combinations then:

cryptsetup -c ${CIPHER} -s ${KEYSIZE} -d /dev/urandom create test /dev/sdc 2>/dev/null
if [ $? = 0 ]; then
      echo "Valid combination: cipher ${CIPHER} size ${KEYSIZE}"
      echo "Invalid combination: cipher ${CIPHER} - size ${KEYSIZE}"
After quite some iterations over a predefined set of combinations (12 ciphers, 7 modes, 14 hashing algorithms, 5 keysizes), there were 1125 valid combinations left. Yeah, testing took a while :-)

Now we wanted to see which combinations performed "best". As stated above, the usecase was a blockdevice for encrypted swap - so "fast, yet pretty secure" were the criteria to look for. As a (very) simple test, the following should be done for each newly set up crypto block device:
while [ $i -lt 30 ]; do
      # Empty all caches, including filesystem buffers  
      sysctl -qw vm.drop_caches=3
      dd if=/dev/mapper/test of=/dev/null bs=1M 2>/dev/null

The results, summarized:
  • cipher_null* is the fastest - but it's absolutely insecure, because...well, it's a NULL cipher :-)
  • Interestingly, PCBC mode is sometimes very slow. As per the Wikipedia article, this mode is not very common anyway, so we'll not choose this one.
  • As expected, Twofish is very fast, along with AES and Blowfish.
Ruling out some of the obvious combinations and omitting some of the "exotic" algorithms, these are my winners:
$ grep -vE 'cipher_null|-(ecb|lrw|pcbc)-|-plain|md[45]|rmd|tgr|crc32|sha1' results | \
    grep ' / 256' | sort -nk5  | head -10
twofish-ctr-essiv:sha256 / 256 : 66            <== 66 seconds for 30 runs. Lower is better.
twofish-cbc-essiv:sha256 / 256 : 69
twofish-xts-essiv:sha256 / 256 : 73
aes-xts-essiv:sha256 / 256 : 79
blowfish-cbc-essiv:sha256 / 256 : 81
blowfish-ctr-essiv:sha256 / 256 : 86
aes-ctr-essiv:sha256 / 256 : 90
aes-cbc-essiv:sha256 / 256 : 91
camellia-xts-essiv:sha256 / 256 : 103
serpent-ctr-essiv:sha256 / 256 : 103

Now my /etc/crypttab proably looks like this:
swap /dev/sda2 /dev/urandom swap,cipher=twofish-xts-essiv:sha256,size=256,hash=sha512
Word of caution: this is a benchmark - some arbitrary test for a very special usecase, executed on one machine and one machine only (Fedora 18 in an ESX virtual machine, equipped with 2 AMD Opteron 848 processors). Before applying these results to your environment, run the benchmark yourself or, better yet: write your own benchmark for your usecase!