AES Java Encryption Performance Benchmarks

Gerrit Jansen van Vuuren
4 min readJun 17, 2019

--

AES CBC+HMAC and GCM performance benchmarks for Java JCE, Bouncy Castle, Commons Crypto and Clojure Buddy.

Overview

When considering which encryption scheme and library to use, ‘correctness’ is always the most important factor. The next important factor is performance.

Why should we care about performance? encryption is slow anyhow right, but how slow? And how much is due to just library implementation decisions? A slow library doesn’t make the encryption scheme more secure.

Performance is important. So much that there even exists special processor instructions for it on some platforms¹-². Using a slow library or too slow a scheme will cause unnecessary response delays, require a higher hardware investment. and may just be impractical on some systems.

Native processor support can make a big difference in numbers, and libraries that use them, and when available, can show huge performance boosts over other libraries that do not. The most common of these instruction sets is Intel’s AES-NI. Java’s JCE providers make use of AES-NI when available since java 1.8⁵. For GCM PCLMULQDQ¹¹ instruction support was added in java 1.9¹²

For this exercise I wanted to run a series of benchmarks for the most common Java encryption libraries (and I sneaked one in from the Clojure community), and see how they perform with a practical configuration.

I used authenticated encryption only, so for AES CBC this means CBC+HMAC and GCM is already authenticated so is used as is.

Enough talking, show me the numbers:

Benchmark Results

Op/s Longer bars are better

[Update: To see more benchmarks and also AES-NI vs no AES-NI see https://github.com/gerritjvv/crypto/tree/master/crypto-perf]

The benchmarks were done with:

The fastest is the Vanilla Java implementation which uses AES-NI and has a low as possible overhead. Bouncy castle is slower, because it does not use AES-NI nor will it ever¹⁰. The apache commons crypto api is considerably slower than expected, even though they claim to use AES-NI.

The worst performer is the Clojure buddy library which is slow not only because it uses bouncy castle but also because it does byte array concatenation using Clojure sequences (think putting a byte array into a Collection). It’s very clear and very readable but has terrible performance. This is too bad because Clojure can actually just call the vanilla java. This is what I’ll be doing from now on in my own code (goodbye buddy :( ).

The results for AES GCM is impressive (double that of aes+hmac in most cases), and the fastest option on all libraries (except bouncy castle which doesn’t use hardware acceleration).

Summary & Remarks

Benchmarks should always be taken with a grain of salt, but I do think the numbers show that going with vanilla Java JCE is a good option.

I’m disappointed that the Clojure lib is so slow, Clojure can be very performant when used correctly.

While writing the benchmarks I found the commons crypto and bouncy castle libraries more difficult to program, than just the Java JCE classes (this is my own biased experience:) ).

Extra Notes Links and Refs

Benchmark details

The benchmarks were run from my 2018 15” MacBook Pro using JHM. You can find the code at https://github.com/gerritjvv/crypto.

I chose a message size of 4kb to test a reasonable sized message, but the aim was to gauge how the different libraries perform. I would encourage you to clone my repo and run your own benchmarks, change message sizes etc, and see what your findings are.

References:

[1] https://www.intel.com/content/www/us/en/architecture-and-technology/advanced-encryption-standard-aes/data-protection-aes-general-technology.html

[2]https://en.wikipedia.org/wiki/AES_instruction_set

[3] https://software.intel.com/en-us/articles/intel-aes-ni-performance-testing-on-linuxjava-stack

[4] https://stackoverflow.com/questions/23058309/aes-ni-intrinsics-enabled-by-default

https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-and-android-part-2-b3b80e99ad36

https://en.wikipedia.org/wiki/Galois/Counter_Mode

[5] The intel benchmarks³ suggest that this can work with java 1.6 with special libraries. I used java 1.10 for my benchmarks and and checked that AES-NI is enabled.

[6] Run: java -XX:+PrintFlagsFinal -version | less

You should see:bool UseAES = true.

The flag is enabled if AES⁴ is detected by default and disabled if AES is not detected.

[7] https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-7616beaaade9

[8] https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-7616beaaade9

[10] https://github.com/bcgit/bc-java/issues/221

[11] https://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode

[12] http://openjdk.java.net/jeps/246

--

--

Gerrit Jansen van Vuuren

A Polygot programmer, who likes learning new things, with an affection for Clojure and functional programming.