AES CBC+HMAC and GCM performance benchmarks for Golang
Please read the updated post here.
The results in this post are not correct due to how I interpreted the golang benchmark output, please read the updated post.
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.
I ran these benchmarks on my 2018 Macbook Pro, “go version go1.12.5 darwin/amd64”. And the code can be found here⁵.
If you compare these results to Java² they are quite low and surprisingly Java can do 40–50K (and GCM > 70K) op/s . I think the main issue(and I cannot find any sure references to this), is that Go does not implement AES-NI¹.
If you compare non AES-NI⁴ the numbers look better for Go AES CBC-HMAC but for AES GCM which should be faster, its still terrible. This becomes worse given that all examples about Go’s encryption I could find on the web always point to using AES GCM. I couldn’t find any resources pointing to AES CBC-HMAC which is another shame because AES-CBC and HMAC should always be used together and with Go’s poor GCM performance is a more performant alternative (again, imho: this is surprising, because GCM is supposed to be faster ).
I like Go for many things. Among them are fast startup times and low overhead.I was expecting some really good numbers for these benchmark results. Unfortunately Go’s encryption performance is not what it should be.
That said, allot of services are being developed in Go and they use encryption directly or indirectly (e.g gRPC⁶ use http²⁷ which most of the times use TLS⁸). These services are working great and people are happy.
An alternative is to use Go without TLS and sidecar with a performant proxy to do the TLS handling or any other encryption requirements, but this just seems to go against Go’s security oriented focus so far.
So the advice is: Use Go, but use another platform/lang for encryption? :(
I would love the Go team to actually make a highly performant AES implementation that use AES-NI (or other hardware optimisations) when available. This would benefit everyone in and outside of the Go ecosystem. Especially given that many services and proxies like Kubernetes and Traefikare written in Go and their performance are surely not what it can be at scale, due to Go’s slow crypto performance.