On SSH ciphers, MACs and key exchange algorithms
Inspired by a some question on StackExchange on the taxonomy of Ciphers/MACs/Kex available in SSH, I wondered what would be the fastest combination of Ciphers, MACs and KexAlgorithms that OpenSSH has to offer.
I've tested with OpenSSH 6.6 (released 2014-03-14) on a Debian/Jessie system (ThinkPad E431). Initially I ran these tests against an SSH server in a virtual machine but realized that the server is not supporting newer Cipher/MAC/KexAlgorithm combinations, so before I ran the actual benchmark I ran ssh-features.sh to test all working combinations. Later on I ended up running the performance test on localhost, making the evaluation step obsolete. Still, I decided to keep it around so that one can peform the benchmark on real-world situations where the remote SSH server is not located on localhost :-)
This OpenSSH version supports 15 different Ciphers, 18 MAC algorithms and 8 Key-Exchange algorithms - that's 2160 combinations to test. ssh-performance.sh will go through the output of ssh-features.sh and transfer a certain amount of data from local /dev/zero to remote /dev/null. Connecting to localhost was fast so I opted to transfer 4GB of data.
Before we get into the details, let's see the top-5 combinations of the results:
cipher: aes192-ctr mac: umac-64-etm@openssh.com kex: ecdh-sha2-nistp256 - 6 seconds cipher: aes192-ctr mac: umac-64-etm@openssh.com kex: diffie-hellman-group1-sha1 - 6 seconds cipher: aes128-ctr mac: umac-64-etm@openssh.com kex: ecdh-sha2-nistp384 - 6 seconds cipher: aes192-ctr mac: umac-64@openssh.com kex: ecdh-sha2-nistp384 - 6 seconds cipher: aes192-ctr mac: umac-64@openssh.com kex: diffie-hellman-group-exchange-sha1 - 6 secondsThe UMAC message authentication code has been introduced in OpenSSH 4.7 (released 2007-09-04) and is indeed the fastest MAC in this little contest. Looking at the results reveals that there indeed some variation in the results when it comes to different MAC or Kex choices. Iterating through all ciphers, we calculate the average run time of each combination:
$ for c in `awk '{print $4}' ssh-performance.log | sort | uniq`; do
printf "cipher: $c "
grep -w $c ssh-performance.log | awk '{sum+=$(NF-1); n++} END {print sum/n}'
done | sort -nk3
cipher: aes128-gcm@openssh.com 8.8125
cipher: aes256-gcm@openssh.com 9.23611
cipher: aes128-ctr 15.6875
cipher: aes192-ctr 15.6944
cipher: aes256-ctr 16.1319
cipher: arcfour 20.26391)
cipher: arcfour128 20.3403
cipher: arcfour256 20.5278
cipher: aes128-cbc 21.125
cipher: aes192-cbc 22.4583
cipher: chacha20-poly1305@openssh.com 23.2361
cipher: aes256-cbc 23.9722
cipher: blowfish-cbc 55.6875
cipher: cast128-cbc 59.5139
cipher: 3des-cbc 200.854
So, aes128-gcm@openssh.com (included in OpenSSH 6.2, released 2013-03-22) comes out fastest across all combinations while 3des-cbc is indeed the slowest cipher.
While the major performance factor is still the choice of the cipher, both MAC and Kex still play a role.
As an example, let's look at aes192-ctr mac, the results range from 6 to 46 seconds:
cipher: aes192-ctr mac: umac-64-etm@openssh.com kex: ecdh-sha2-nistp256 - 6 seconds [...] cipher: aes192-ctr mac: hmac-sha2-256-etm@openssh.com kex: ecdh-sha2-nistp256 - 46 secondsLet's see how MAC and Kex choices rank up across all (15) different ciphers. That is, we calculate the average time for each MAC:
$ for m in `awk '{print $6}' ssh-performance.log | sort | uniq`; do
printf "mac: $m "
grep -w $m ssh-performance.log | awk '{sum+=$(NF-1); n++} END {print sum/n}'
done | sort -nk3
mac: umac-64@openssh.com 28.45
mac: umac-64-etm@openssh.com 28.8167
mac: umac-128-etm@openssh.com 29.8583
mac: umac-128@openssh.com 30.1
mac: hmac-sha1-96 33.4417
mac: hmac-sha1-96-etm@openssh.com 33.5167
mac: hmac-md5-etm@openssh.com 33.6333
mac: hmac-sha1 33.7104
mac: hmac-md5-96 33.7792
mac: hmac-md5-96-etm@openssh.com 33.8167
mac: hmac-md5 33.825
mac: hmac-sha1-etm@openssh.com 34.2
mac: hmac-sha2-512-etm@openssh.com 38.2333
mac: hmac-sha2-512 38.2833
mac: hmac-ripemd160-etm@openssh.com 43.775
mac: hmac-ripemd160 43.7792
mac: hmac-sha2-256 44.3792
mac: hmac-sha2-256-etm@openssh.com 44.45
And again for the key exchange algorithms:
$ for k in `awk '{print $8}' ssh-performance.log | sort | uniq`; do
printf "kex: $k "
grep -w $k ssh-performance.log | awk '{sum+=$(NF-1); n++} END {print sum/n}'
done | sort -nk3
kex: ecdh-sha2-nistp256 35.2926
kex: diffie-hellman-group14-sha1 35.3148
kex: diffie-hellman-group1-sha1 35.4296
kex: diffie-hellman-group-exchange-sha256 35.563
kex: ecdh-sha2-nistp521 35.563
kex: diffie-hellman-group-exchange-sha1 35.6926
kex: ecdh-sha2-nistp384 35.8333
kex: curve25519-sha256@libssh.org 35.8667
The differences for Kex here are in the sub-second range, so even the recently added Curve25519 option would not be much of a performance impact here.So, what do we make of all this? Another StackExchange question suggests that SSH in general holds up pretty good security-wise and even dismisses problems with CBC. Assuming all of that is true, what can we do to get the most performance when transferring big files over SSH? Let's look at the defaults again, from ssh_config(5) of OpenSSH 6.6:
Ciphers: aes128-ctr aes192-ctr aes256-ctr arcfour256 arcfour128 aes128-gcm@openssh.com [...] MACs: hmac-md5-etm@openssh.com hmac-sha1-etm@openssh.com umac-64-etm@openssh.com [...] KexAlgorithms: curve25519-sha256@libssh.org ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 [...]So, according to the results of this little contest, a faster default for a recent version of OpenSSH could be:
Ciphers aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,\
aes128-ctr,arcfour256,arcfour128
MACs umac-128-etm@openssh.com,umac-64-etm@openssh.com,umac-128@openssh.com,umac-64@openssh.com
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256
Notes:
- The GCM ciphers have been implemented with OpenSSH 6.2 (released 2013-03-22).
- The EtM (Encrypt-then-MAC) modes and 128-bit UMAC variants have only been supported since OpenSSH 6.2 (released 2013-03-22).
- The
KexAlgorithmsoption has been added with OpenSSH 5.7 (released 2011-01-24)
Update October 2014): OpenSSH 6.7 disables the CBC ciphers by default because of vulnerabilites found when used with SSH (found in 2008).
Update (June 2016): new benchmark script and new results (averaged over 3 runs):
### Top-5 overall cipher: aes128-ctr mac: umac-64@openssh.com kex: curve25519-sha256@libssh.org - 10 seconds avg. cipher: aes128-ctr mac: umac-64@openssh.com kex: ecdh-sha2-nistp521 - 10 seconds avg. cipher: aes128-ctr mac: umac-64@openssh.com kex: diffie-hellman-group-exchange-sha256 - 10 seconds avg. cipher: aes128-ctr mac: umac-64@openssh.com kex: diffie-hellman-group14-sha1 - 10 seconds avg. cipher: aes128-ctr mac: umac-64@openssh.com kex: ecdh-sha2-nistp256 - 9 seconds avg.
If we were to use the Secure Secure Shell recommendations and exclude some of the weaker choices, we would lose only a few seconds (and would basically switch to
chacha20-poly1305):
### Top-6 overall cipher: aes128-gcm@openssh.com mac: hmac-sha2-256-etm@openssh.com kex: curve25519-sha256@libssh.org - 14 seconds avg. cipher: chacha20-poly1305@openssh.com mac: umac-128-etm@openssh.com kex: diffie-hellman-group-exchange-sha256 - 13 seconds avg. cipher: chacha20-poly1305@openssh.com mac: hmac-ripemd160-etm@openssh.com kex: curve25519-sha256@libssh.org - 13 seconds avg. cipher: chacha20-poly1305@openssh.com mac: hmac-sha2-256-etm@openssh.com kex: curve25519-sha256@libssh.org - 13 seconds avg. cipher: chacha20-poly1305@openssh.com mac: hmac-sha2-256-etm@openssh.com kex: diffie-hellman-group-exchange-sha256 - 13 seconds avg. cipher: chacha20-poly1305@openssh.com mac: umac-128-etm@openssh.com kex: curve25519-sha256@libssh.org - 12 seconds avg.