BoringSSL is a Google fork of OpenSSL. It includes various interesting patches, including an implementation of the ChaCha20 cipher. In addition, BoringSSL allows you to group cipher suites of equal preference:
In this article I show you how you can tweak your nginx configuration to take advantage of this feature.
AES with AES-NI outperforms ChaCha20
AES with AES-NI makes encryption fast. Blazingly fast. For example, here is a benchmark I just took from the server running this website (a modest Intel Xeon E3-1220 V2 @ 3.10GHz):
Did 20341000 AES-128-GCM (16 bytes) seal operations in 3000099us (6780109.6 ops/sec): 108.5 MB/s Did 2356000 AES-128-GCM (1350 bytes) seal operations in 3000761us (785134.2 ops/sec): 1059.9 MB/s Did 438000 AES-128-GCM (8192 bytes) seal operations in 3002910us (145858.5 ops/sec): 1194.9 MB/s Did 17839000 AES-256-GCM (16 bytes) seal operations in 3000160us (5946016.2 ops/sec): 95.1 MB/s Did 2092000 AES-256-GCM (1350 bytes) seal operations in 3000884us (697127.9 ops/sec): 941.1 MB/s Did 388000 AES-256-GCM (8192 bytes) seal operations in 3004207us (129152.2 ops/sec): 1058.0 MB/s Did 7779000 ChaCha20-Poly1305 (16 bytes) seal operations in 3000332us (2592713.1 ops/sec): 41.5 MB/s Did 1139000 ChaCha20-Poly1305 (1350 bytes) seal operations in 3001412us (379488.1 ops/sec): 512.3 MB/s Did 220000 ChaCha20-Poly1305 (8192 bytes) seal operations in 3006395us (73177.3 ops/sec): 599.5 MB/s
As you can see from the results above, nothing beats AES with hardware acceleration – not even ChaCha20, which is impressively fast too given that it’s a software only cipher implementation.
ChaCha20 outperforms AES without AES-NI
Not every platform supports AES hardware acceleration though. Think of all the different types of clients connecting to this website. Many of them are ARM-powered mobile devices, Android or iOS for example, neither of which have hardware support for AES. So even if my server can handle the AES routines crazy fast, those devices would have to work a lot harder as they’re browsing this website. In this case, wouldn’t it make sense to switch to ChaCha20 instead, which not only reduces latency (= faster page loads) but also safes battery power?
Google ran a few tests:
Best of two worlds: AES and ChaCha20 in an equal preference group with BoringSSL
How do you enable group cipher suites of equal preference? You can find the info in the ssl_cipher_process_rulestr() function in ssl/ssl_ciph.c. To group ciphers, you seperate them using the OR symbol (|) and then enclose the group with square brackets, like this:
So for all nginx aficionados, here is the server-preferred cipher list I currently use (nginx must be build against boringssl):
ssl_ciphers [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECD HE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384;
As a result, if you are visiting this site with Chrome on an iPhone or Android device, you’ll be using the ChaCha20 cipher.
On the other hand, if you’re visiting with Chrome on a Windows 7 machine with AES-NI support, you’ll be using the AES-GCM cipher instead.
5 thoughts on “Optimize AES and ChaCha20 usage with BoringSSL”
Latest stable Chrome (37) / Opera (24) also has Chacha20 + Poly1305 cipher support on Windows, and is always the top choice during Client Hello.
Hi Abel, it’s good to hear that Opera added Chacha20 as well. When you say that it’s the top choice during Client Hello, I assume that the computer you tested it on doesn’t have hardware acceleration for AES (like AES-NI with modern Intel CPUs). Otherwise AES-GCM should show as the top choice (the most preferred cipher).
In fact, Chrome for instance requires not only the AES-NI CPU flag but also AVX. See here: https://code.google.com/p/chromium/issues/detail?id=346086
Yes you’re dead-on about the CPU; the old i7 used for testing was released before Intel has any AES-enabled CPU. I was not aware of this instruction set detection.
But why is Chacha20 better than AES?
I know this posting is old but could somebody tell me why
> ssl_ciphers [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECD …
is better than
> ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECD …
In the assumption that clients who doesn’t support POLY1305 support AES-NI (from my knowledge only Android has implemented POLY1305 at large scale) this should already solve the problem without requiring new code.