Sometimes you just need to encrypt a file. Not set up a key management system, not learn the gpg command line again, not pull a heavy dependency — just turn secrets.txt into secrets.bin with a key you control. That’s the niche gocrypt fills for me.
Why it exists
I wrote gocrypt years ago for shell scripts that needed to round-trip files through a backup pipeline. It needed to be a single static binary, work on Linux and macOS, and not require interactive prompts. Since then it has grown one important feature: it now uses AES-GCM, which gives you authenticated encryption — tampering with the ciphertext makes decryption fail loudly instead of producing garbage.
I’ll be upfront: if you’re starting from scratch today, you should probably look at age first. It’s more modern, more carefully designed, and has a real key management story. gocrypt is for the case where you already have a 16- or 32-byte key, you want a tiny self-contained tool, and AES is what your team has settled on.
A breaking-change warning
Version 2 switched from CBC to AES-GCM. That means:
- Files encrypted with v1 cannot be decrypted with v2.
- Files encrypted with v2 cannot be decrypted with v1.
If you have a v1 archive, decrypt it with the old version first, then re-encrypt with v2.
Install
Homebrew is the easiest:
brew tap sgaunet/homebrew-tools
brew install sgaunet/tools/gocrypt
Or grab a release binary from the releases page and drop it on your PATH. There’s no public Docker image, but the binary is single-file static so adding it to your own image is trivial.
Usage
The CLI is two verbs: enc and dec. Same flags for both.
# Encrypt with a 32-byte key (AES-256)
gocrypt enc --i input.txt --o encrypted.bin --k keyfile.txt
# Decrypt
gocrypt dec --i encrypted.bin --o decrypted.txt --k keyfile.txt
The key length picks the AES variant:
- 16 bytes -> AES-128
- 32 bytes -> AES-256
Anything else and the tool refuses to run. That’s the whole interface.
Keys from environment
Passing --k is fine for ad-hoc use, but in CI you usually want the key to come from a secret store rather than land on disk. gocrypt reads GOCRYPT_KEY directly:
export GOCRYPT_KEY="0123456789abcdef0123456789abcdef"
gocrypt enc --i secrets.yaml --o secrets.yaml.enc
The variable wins over a key file when both are set, so you can override per-job in a pipeline without rewriting scripts.
Using it inside another container
The Docker image isn’t meant to be docker run’d — it exists so you can copy the binary into your own image:
FROM sgaunet/gocrypt:latest as gocrypt
FROM alpine:latest
COPY --from=gocrypt /gocrypt /usr/local/bin/gocrypt
That keeps your runtime image small and lets you bake in encryption support without a Go toolchain.
Where to find it
- Source: github.com/sgaunet/gocrypt
- License: MIT
- Recommendation: for greenfield projects, evaluate age first. For “I have an AES key, I have a file, leave me alone” —
gocryptdoes the job.
It’s open source, MIT-licensed, and intentionally small. No surprises.