Benchmarking SSH connection: What is the fastest cipher algorithm for RPi?

Hi, this is flownspores who is working at TwoGate inc. This article is my first one! And this is the first of my english blog article in my life. If you find any weird grammar mistakes or misspells, feel free to comment below.

Making the fastest SSH connection

I set up my raspberry pi 3's sshd then I just wondered about performance. Raspberry pi 3 has a tiny ARM cpu with no AES acceleration. Recent Intel or AMD's cpus have AES-NI which can accelerate AES encryption and decryption.

Without AES acceleration, which cipher algorithm is the fastest? That's my question.

I also want to test key exchange algorithms and MAC algorithms. Key exchange algorithm is used to establish of ssh connection (and during rekeying). Public-key cryptography is a secure way to communicate, but it is too slow to use every transfer. So that symmetric-key algorithms are used during data transfer. Public-key encryption is only used to encrypt symmetric-key. Key exchange algorithm is the way to exchange symmetric-key in a secure way. I am not a specialist in this domain, so you may read more details about ssh encryption on the Internet.

Testing ssh algorithms

There are several items in SSH configuration that can be changed, and I compared the algorithms for each. Key exchange algorithms (Kex), Algorithms of Message authentication code (MAC), Cipher algorithms.

KexAlgorithm

SSH's KexAlgorithm is a key exchange algorithm. You can see algorithms which can be used in your ssh connection.

$ ssh -Q kex
diffie-hellman-group1-sha1
diffie-hellman-group14-sha1
diffie-hellman-group14-sha256
diffie-hellman-group16-sha512
diffie-hellman-group18-sha512
diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256
ecdh-sha2-nistp256
ecdh-sha2-nistp384
ecdh-sha2-nistp521
curve25519-sha256
curve25519-sha256@libssh.org
sntrup4591761x25519-sha512@tinyssh.org

  Diffie-hellman (DH) key exchange is common in the past but newer algorithms like ECDH or curve25519 have appeared.

So the kex algorithm is used only in establishing the connection*1, I just write the code which simply connects the server and executes : then quickly disconnects. : is a command which does nothing.

ssh -v  -o "ControlMaster=no" -o "ControlPath=none" -o "Compression=no" -o "KexAlgorithms=..." host :

As you can see, I wrote some additional options: "ControlMaster/Path=no" and "Compression=no". ControlMaster/ControlPath option is to multiplex ssh connections which holds persistent connections to the server. At this time, this feature bothers my testing so it should be turned off. Compression is also unnecessary feature during test*2.

I've tested each KexAlgorithms per 5 times. Then I calculated the median value of each algorithm. The graph is shown below.

  • Testing environment
    • Client: Mac mini 2018 Core i7-8700B equipped with 10Gb Ethernet
      • macOS Catalina, OpenSSH_8.1p1, LibreSSL 2.7.3
    • Server: Raspberry Pi 3B+ with Heat sink
      • Debian 10 (Raspberry Pi OS)
    • Network: 1GbE
      f:id:flownspores:20200730053131p:plain
      SSH KeyExchange Algorithm Performance Comparison

As you can see from the graph, the fastest key exchange algorithm is ecdh-sha2-nistp256. The slowest is diffie-hellman-group-exchange-sha256. Curve25519-* appears to be doing well. SHA1 is considered to be obsolete, so you may not use diffie-hellman-group14-sha1.

I will use curve25519-sha256 which is a great balance of speed and security.

MACs

MAC stands for message authentication code, which is like a hash function. (This is a very rough explanation. You may read some informative information on the Internet.)

You can get MAC algorithms to type ssh -Q mac that can be used in your ssh command.

$ ssh -Q mac
hmac-sha1
hmac-sha1-96
hmac-sha2-256
hmac-sha2-512
hmac-md5
hmac-md5-96
umac-64@openssh.com
umac-128@openssh.com
hmac-sha1-etm@openssh.com
hmac-sha1-96-etm@openssh.com
hmac-sha2-256-etm@openssh.com
hmac-sha2-512-etm@openssh.com
hmac-md5-etm@openssh.com
hmac-md5-96-etm@openssh.com
umac-64-etm@openssh.com
umac-128-etm@openssh.com

MAC is used only for non-AEAD encryption like aes256-ctr, aes256-cbc. AEAD encryption like aes256-gcm already has an MAC-ish authentication algorithm itself, so I use encryption of aes256-gcm at this time.

Sending large file to Raspberry pi

The test is transferring a 100MiB file by scp. Measuring time of sending client to server (/dev/null). Yes I know that scp is outdated today, but sftp is complex to use from programs. Rsync can't write out to /dev/null. that's why i use scp.

  • Tesing environment
    • hardware configuration is same as before.
    • using aes256-ctr as cipher

f:id:flownspores:20200730060011p:plain
SSH MAC Algorithm Performance Comparison (Client to RPi)

The fastest algorithm is umac-64@openssh.com and umac-128-etm@openssh.com. The slowest is hmac-sha2-512.

ETM means encrypt-then-mac, which is considered stronger than non-ETM (like MAC-then-Encrypt). You should use *-etm over non-ETM.

Note that MAC option is not effective if you use AEAD encryption (like AES-GCM). AES-GCM is preferred over non-GCM for security reasons.

Receiving large file from Raspberry pi

f:id:flownspores:20200730065341p:plain
SSH MAC Algorithm Performance Comparison (RPi to Client)

The fastest is umac-64@openssh.com and umac-64-etm@openssh.com. umac-128-etm@openssh.com and umac-128@openssh.com is also fast enough.

umac-*s are the best choice for both sending and receiving.

Ciphers

Finally I have tested cipher algorithms. RC4 (arcfour) is considered the fastest algorithm on non-AES accelerated CPUs. But RC4 is considered a weak algorithm today. It is not usable algorithms in my OpenSSH:

$ ssh -Q cipher
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

I use these algorithms for testing at this time.

  • Tesing environment
    • hardware configuration is same as before.
    • for non-AEAD cipher, umac-128-etm@openssh.com as MAC
    • 100MiB transfer, same as before

Can't wait to see the results? Let's see.

Sending large file to Raspberry pi

f:id:flownspores:20200730062432p:plain
SSH Cipher Algorithm Performance Comparison (Client to RPi)
Surprisingly, the newest algorithm chacha20-poly1305@openssh.com is the slowest 😭. The fastest is aes128-ctr. Why? When I transferring large file from Mac mini, mini's AES-NI hardware acceleration is used for encryption. So this test is not informative for raspberry pi's performance index.

Receiving large file from Raspberry pi

So I've also tested reverse transmission. Client to RPi. But the results are not much different.

f:id:flownspores:20200730070551p:plain
SSH Cipher Algorithm Performance Comparison (RPi to Client)

The fastest is aes128-ctr. *-ctrs are the fastest in this test. The transfer rate may be capped by the bandwidth of the Raspberry Pi's SD card.

Despite these results, I would still use *-gcm for security reason.

Conclusion

If you want to harden security with small amount of speed sacrifice:

  • curve25519-sha256 as KexAlgorithms
  • aes*-gcm@openssh.com as Ciphers

If you want the fastest connection (not so bad for security), use:

  • ecdh-sha2-nistp256 as KexAlgorithms
  • umac-*-etm@openssh.com as Macs
  • aes128-ctr as Ciphers

Benchmarking script

I've tested the performance of ssh in various algorithms by this script. This is an automated script that connects host with many different ssh configurations. Then this script writes CSV files. Each test is executed only one time, so you may need to run the test repeatedly to get accurate results. If you run this script for remote server over the Internet, results may not be accurate. So you might be better using it for local network.

*1:Strictly speaking, KeyExchange is also occurs during rekey.

*2:Mac/cipher test shown below is transferring large random data. Generally speaking, random data has high entropy which can't be compressed.