Benchmarking SSH Ciphers

Whenever I’ve got a lot of data to transfer I usually kick off the rsync or scp with the default SSH settings and then, after an hour or so, wonder if I could have sped things up with a different cipher.

So I decided to find out now for my future self and maybe save some time.

A quick not about SSH Ciphers

SSH uses several ciphers and algorithms. I have encountered lots of sysadmins that think their choice of SSH key determines their transfer speed. SSH keys are only used by SSH to transmit the shared key that is used for the symmetric cipher which encrypts all of the session data. The admins SSH key does not affect the transfer speed only the choide symmetric cipher does.

The cipher can be manually set when starting an SSH session using the -c <CIPHER> option.

The list of ciphers that your versions of SSH supports is printed with ssh -A ciphers. On my two Ubuntu 20.04 test servers this is:

# ssh -Q ciphers
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
rijndael-cbc@lysator.liu.se
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com

So these are the ones I’m going to test.

The Setup

First, all of these ciphers need enabling on both sides. I did this by editing /etc/ssh/sshd_config and adding the following line:

Ciphers 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com

Next, I generated a 500MB file of random data:

dd if=/dev/urandom of=rand.file bs=1MB count=500

Then, I spun up a couple of DigitalOcean droplets with a VLAN between them which I used for these tests.

Results

First, I tested the how fast the disk was:

dd if=rand.file of=/dev/null

Then how fast an unencrypted transfer between the servers. I used netcat for that as follows:

Sender:
dd if=rand.file | nc <IP> 8080

Receiver
nc 8080 -l >/dev/null

And finally, using SSH with the following command:

dd if=rand.file | ssh -o 'Compression no' -c <CIPHER> <USER>@<IP> dd of=/dev/null

These are the numbers I got:

Speed
Raw disk read 183 MB/s
Unencrypted 83.2 MB/s
3des-cbc 14.1 MB/s
aes128-cbc 75.7 MB/s
aes192-cbc 74.1 MB/s
aes256-cbc 68.9 MB/s
rijndael-cbc@lysator.liu.se 64.6 MB/s
aes128-ctr 67.4 MB/s
aes192-ctr 69.5 MB/s
aes256-ctr 68.2 MB/s
aes128-gcm@openssh.com 65.3 MB/s
aes256-gcm@openssh.com 65.0 MB/s
chacha20-poly1305@openssh.com 67.0 MB/s

The CPU was at or around 100% during all of these transfers so it was all down the the efficiency of the ciphers.

The winner is aes128-cbc. So if you are looking to speed up a transfer choose that one. Here are the commands for rsync:

rsync -e `ssh -c aes128-cbc` rand.file user@example.com:/home/user/rand.file

And scp:

scp -c aes128-cbc rand.file user@example.com:/home/user/rand.file