AES Golang Encryption Performance Benchmarks Updated

Gerrit Jansen van Vuuren
3 min readJun 30, 2019

--

AES CBC+HMAC and GCM performance benchmarks for Golang

Overview

Apart from correctness encryption performance is a very important factor for any application that requires secure data. This goes from password managers (like my own pkhub.io) to web servers using Https, micro services with secure communication (anything https/tls, gRPC), proxies, reverse proxies, dbs with disk encryption etc….

The more CPU time spent on encrypting or decrypting the slower your service is and the more servers you need. For some programs, like just downloading a file from s3 no amount of hardware will make it download the file faster, see this issue³.

Go is a very hot topic these days, and especially if you’re writing micro services (or just software) in Kubernetes. So I have decided to take a look at Go’s AES encryption performance, using Java’s JCE as my baseline.

Benchmark Results

Go’s AES encryption performance, using Java’s JCE as my baseline.

Op/s Longer bars are better. Golang AES CBC & GCM with Java comparison

I ran these benchmarks on my 2018 Macbook Pro, “go version go1.12.5 darwin/amd64”. And the code can be found here⁵.

How I tested:

This is an update to my last golang encryption benchmarking post, in which I found that I interpreted the golang benchmark output completely wrong. I also learned while investigating a bit that currently (go v1.12) benchmark results cannot be used to calculate operations per second⁹. See this post for a complete explanation.

So I have tried a naive approach, using multiple runs with start to end time measurements. The numbers look much better for go.

If you just run the golang benchmarks you average latency numbers. For example, if you run AES+GCM as a golang benchmark you get output like: 300000 runs with an average like 4732 ns/op. And if you try to use this to get the throughput ops/s you get 300000/ (4732/1000 000 000), which is 63 398 140 321 ops/s. Now this number can’t possibly be the AES+GCM per second, you won’t even reach this if you write everything in fortran.

What you need for benchmarking is throughput and not (latency) average time spent.

So what I did was:

  1. In each test method I do a warmup of the method to test, 1million times. This is for good health.
  2. Then execute 10 runs where each run calls the method to test, 1million times. The execution time is recorded before and after each run.

This means for an execution time of 4s go has executed to method 1million times in 4 seconds.

Note here 1million is 1000 000.

I did several runs and found the results to be pretty stable. I took the best (shortest time) from each and used that in the graph above.

Is this a perfect way of testing? Not perfect no, and I’m definitely looking forward to this PR being merged. But I do think its good enough for a simple comparison benchmark, and its definitely better than trying to conjure how to make golang benchmark results into operations per second.

The results from my own test runs are:

Summary

These performance values and especially the AES+GCM look very good. Especially golang’s AES+GCM. I’m glad that I investigated more into why the values from my previous golang encryption benchmarking post⁹ were so low.

All in all, benchmark results are entertaining to look at but I’d advise you to run your own before reaching conclusions.

PS:

These benchmarks came about from my work on https://pkhub.io. I’m using Go for the client cli side and was curious as to its encryption performance. I’ve long been frustrated with password and credential management tools for developers. This brought me to write my own DevOps Password Manager. Check it out, it might save you the frustration of manually managing credentials.

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://medium.com/@gerritjvv/aes-java-encryption-performance-benchmarks-3c2cb19a40e9?source=friends_link&sk=37a8cebe0b14c03db759e0d31874e74e

[3] https://github.com/goamz/goamz/issues/81

[4] https://github.com/gerritjvv/crypto/tree/master/crypto-perf

[5] https://github.com/gerritjvv/crypto/tree/master/crypto2

[6] https://github.com/grpc/grpc-go

[7] https://httpwg.org/specs/rfc7540.html

[8] https://github.com/containous/traefik/issues/2139

[9] https://www.mikenewswanger.com/posts/2018/benchmarking-in-go/

--

--

Gerrit Jansen van Vuuren

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