Using libsodium in Lambda, with Go

Sean Schulte
3 min readMar 19, 2018

--

If you’ve been reading along, you already saw how to build and package libsodium so we can use it in Lambda when our function is written in Clojure.

I don’t know about you, but I run a polyglot system. Many of my Lambda functions are written in Clojure, but sometimes I need those functions to start up a little faster than Lambda’s Java8 environment can possibly do. Sometimes, what I need is Go.

But the data in S3 is encrypted! We need to be able to deal with that in our Go program. This time around, we’ll use github.com/jamesruan/sodium to work with it.

Encrypting isn’t quite as easy as it is in Clojure, but it’s still pretty easy:

func Encrypt(plaintext, k []byte) ([]byte, error) {
nonce, err := randomNonce()
if err != nil {
return nil, err
}
cyphertext := sodium.Bytes(plaintext).SecretBox(
sodium.SecretBoxNonce{nonce},
sodium.SecretBoxKey{k})
return append(nonce, cyphertext...), nil
}

Decrypting is, too:

func Decrypt(cyphertext, k []byte) ([]byte, error) {
nonce := sodium.SecretBoxNonce{cyphertext[:NONCE_LEN]}
enc := sodium.Bytes(cyphertext[NONCE_LEN:])
return enc.SecretBoxOpen(nonce, sodium.SecretBoxKey{k})
}

What’s randomNonce? Well:

const NONCE_LEN int = 24func randomNonce() ([]byte, error) {
b := make([]byte, NONCE_LEN)
_, err := rand.Read(b)
return b, err
}

Okay, cool. We have code that can use it. I mean, once that package has its imports:

import (
"crypto/rand"
"github.com/jamesruan/sodium"
)

And, just as before, we need to convert the key to/from a string, since we need to pass it in as an environment variable but use it as a byte array. Go’s hex.DecodeString from the encoding/hex package gets the job done for us.

It stands to reason that we can use the same procedure to build that binary that we used when we packaged up that Clojure function. And that’s almost true! This, once again, is in our EC2 instance running the Lambda AMI:

sudo yum install -y gcc gcc-c++
wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.15.tar.gz
tar xzf libsodium-1.0.15.tar.gz
cd libsodium-1.0.15
./configure
sudo make install

That gets the binary, but our Go program doesn’t compile yet.

sudo cp libsodium.pc /usr/lib64/pkgconfig/

Now it does! pkgconfig threw me for a loop for a while.

As you may already be aware, when you deploy a Go program in Lambda, you need to put the binary into a ZIP file. When it’s a regular ol’ Go program, that might seem a little weird, since it’s a ZIP with just one file in it:

zip my-program.zip my-program

But it turns out it’s pretty convenient, because now we need a lib/ directory inside that ZIP, next to our program.

zip my-program.zip my-program lib/*

The ZIP looks like this now:

Length      Date      Time    Name
--------- ---------- ----- ----
14757968 03-16-2018 20:02 my-program
2514968 03-16-2018 21:43 lib/libsodium.so
2514968 03-16-2018 21:43 lib/libsodium.so.23
2514968 03-16-2018 21:43 lib/libsodium.so.23.0.0
--------- -------
22302872 4 files

And we can deploy it as normal. Now we can encrypt and decrypt our data in Lambda, whether we happened to write our function in Clojure or in Go.

--

--

Sean Schulte
Sean Schulte

No responses yet