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.854So, 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.45And 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.8667The 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-nistp256Notes:
- 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
KexAlgorithms
option 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.