Cryptare v1.3.2 — Stored-Key Encryption, Signed Releases, and a Container Image
I am excited to announce Cryptare v1.3.2, the release that makes stored keys do what they were always meant to do!
Cryptare is a Go terminal tool for encrypting, decrypting, compressing, and extracting files and directories. It combines a scriptable command-line interface with an interactive terminal UI and a small local store for password-protected keys. Files are encrypted with AES-256-GCM, streamed in authenticated chunks, under a key derived from your password with Argon2id.
v1.0.0 shipped on September 14. Since then, six releases have reworked the file format, the password handling, and the release pipeline. v1.3.2 lets you encrypt with a key from the key store instead of a password, gives every key a single password, and ships each release with signed build provenance and a container image on GitHub Container Registry.
$ cryptare keys generate --password-file master.txt
Generated key: ab0430cd1abad9e0
$ cryptare keys list
KEY ID ALGORITHM CREATED
ab0430cd1abad9e0 AES-256-GCM 2026-10-05 10:25
$ cryptare encrypt report.pdf --key ab0430cd1abad9e0 --password-file master.txt
Encrypted: report.pdf → report.pdf.enc
$ cryptare decrypt report.pdf.enc
Enter master password for key ab0430cd1abad9e0:
Decrypted: report.pdf.enc → report.pdf
What’s new in v1.3.2
- Encrypt with a stored key
cryptare encrypt <path> --key <key-id>(or-k) encrypts a file or folder with a key from the key store instead of a password; the TUI has a matching “Stored key ID” fielddecryptneeds no extra flag: it reads the key’s ID from the file’s header, takes the key from the key store, and asks for its master password- Each file gets a key of its own, derived from the stored key and the file’s random salt with HKDF-SHA256
- A file encrypted with a stored key can only be decrypted with that key, so keep an export of every key you encrypt with (
cryptare keys export) somewhere other than the key store.keys deletenow says so before it asks you to confirm
- One password per key
keys exportasks for the key’s master password, checks it against the key, and protects the export with itkeys importchecks that the key inside the export opens before it stores it- Exports made by v1.3.1 or earlier with a separate export password still import: give the second password with
--export-password-file, at the prompt, or in the TUI’s second password field
- Cleaner errors
- A command that fails prints the error without the whole usage text after it; only mistakes in the command line itself, such as an unknown flag or a missing argument, show usage
- Container image
- Published to GitHub Packages as
ghcr.io/jabbott-iii/cryptare, tagged1.3.2,1.3, andlatest - Built for
linux/amd64with CGO, from base images pinned by digest - Runs as an unprivileged user (UID
10001) and keeps its key store in the/app/datavolume
- Published to GitHub Packages as
- Signed build provenance
- Every release archive,
checksums.txt, and the container image carry a signed SLSA build provenance attestation from the release workflow, so you can check that a download was built from this repository’s tagged source
- Every release archive,
- Format compatibility tests
- Golden fixtures (encrypted files, folders, stored keys, and key exports written by earlier releases, plus files in the new stored-key format) must keep opening in every build, so a format change can’t silently lock anyone out of their files
- For contributors
make checkruns CI’s checks locally, in CI’s order;make check-alladds gosec, govulncheck, and the workflow linter- The linters and scanners run at CI’s pinned versions through
go run, so there is nothing extra to install
- Security policy
- SECURITY.md explains how to report a vulnerability privately; reports are acknowledged within 7 days, and the 1.3.x line receives security fixes
Since v1.0.0
If you last looked at Cryptare in the v1.0.0 post, here is what changed along the way:
- Release binaries that run. The v1.0.0 binaries were built without CGO and exit on every command; v1.0.1 and later work. The Linux binaries are statically linked against musl, so they run on any distribution, and release archives now include
LICENSE,NOTICE, andTHIRD_PARTY_LICENSES.txt - A versioned file format. Argon2id key derivation (64 MiB of memory, 3 passes, 4 lanes) and streaming encryption in authenticated chunks, so memory use doesn’t grow with file size. Files from earlier versions still open, with nothing to convert; the README’s upgrade notes cover the few exceptions
- Better password handling. The prompt reads the whole line, hides what you type, and asks you to confirm a new password. New passwords must be at least 15 characters.
--password-filekeeps passwords out of your shell history, and passwords are Unicode-normalised (NFKC), so the same password matches however its characters were typed - Safe outputs. Nothing is overwritten without
--force, outputs are written atomically, and Ctrl+C removes unfinished output - Safer extraction.
decompress, anddecryptof an encrypted folder, stop at 10 GiB of output or 100,000 entries by default (--max-size,--max-entries), and on Linux and macOS extracted files are private to you - A per-user key store. Keys live in your user data folder instead of the current folder;
cryptare keys pathshows where - More formats and conveniences. ZIP archives (
compress --format zip),decompress --raw,--version, and vim-style TUI bindings (cryptare --vim)
Example uses
# Protect a document before copying it to a USB drive or cloud storage
cryptare encrypt ./tax-return.pdf
# Back up a project folder as one encrypted file, then restore it later
cryptare encrypt ./project-dir --output ./project-dir-backup.enc
cryptare decrypt ./project-dir-backup.enc --output ./restored-project-dir
# Encrypt with a stored key instead of choosing a password for each file
cryptare keys generate # prints "Generated key: <key-id>"
cryptare encrypt ./report.pdf --key 3f9a1c0e7b2d4a6f
cryptare keys export 3f9a1c0e7b2d4a6f --output /media/backup/3f9a1c0e7b2d4a6f.ckey
# In scripts, read the password from a file only you can read
cryptare encrypt ./secret.txt --password-file ~/.config/cryptare/pw.txt
# Package build output as a zip, and extract a large archive with a higher limit
cryptare compress ./build --format zip
cryptare decompress ./huge-dataset.tar.gz --max-size 50GiB
# Use menus instead of flags
cryptare --vim
Installation
Download the archive for your platform and checksums.txt from the v1.3.2 release:
| Platform | Archive |
|---|---|
| Linux (x86-64) | cryptare_linux_amd64.tar.gz |
| Linux (ARM64) | cryptare_linux_arm64.tar.gz |
| macOS (Apple Silicon) | cryptare_darwin_arm64.tar.gz |
| macOS (Intel) | cryptare_darwin_amd64.tar.gz |
| Windows (x86-64) | cryptare_windows_amd64.zip |
On Linux (use linux_arm64 in place of linux_amd64 on ARM64):
BASE=https://github.com/jabbott-iii/Cryptare/releases/download/v1.3.2
curl -LO "$BASE/cryptare_linux_amd64.tar.gz"
curl -LO "$BASE/checksums.txt"
sha256sum --ignore-missing -c checksums.txt
tar -xzf cryptare_linux_amd64.tar.gz
chmod +x cryptare_linux_amd64
sudo mv cryptare_linux_amd64 /usr/local/bin/cryptare
cryptare --version
On macOS, use the matching darwin archive the same way and check its hash with shasum -a 256. On Windows, extract the zip, rename cryptare_windows_amd64.exe to cryptare.exe, and add it to your PATH. There is no Windows ARM64 build.
Container image
docker pull ghcr.io/jabbott-iii/cryptare:1.3.2
docker run --rm -it -v cryptare-data:/app/data ghcr.io/jabbott-iii/cryptare:1.3.2
This opens the TUI with its key store in the cryptare-data volume. To use a folder on the host instead, run the container as your own user with --user "$(id -u):$(id -g)", as the README’s Docker section shows.
Building from source
Building needs Go 1.26 or newer and a C compiler (gcc or clang) with CGO enabled, because the SQLite driver behind the key store uses CGO. On Windows, use a MinGW-w64 toolchain and run make from Git Bash.
git clone https://github.com/jabbott-iii/Cryptare.git
cd Cryptare
git checkout v1.3.2
make build
./bin/cryptare --version
Verifying build provenance
checksums.txt shows that a download wasn’t damaged; the attestation shows where it came from. Verify an archive or the image with the GitHub CLI (after gh auth login):
gh attestation verify cryptare_linux_amd64.tar.gz --repo jabbott-iii/Cryptare \
--signer-workflow jabbott-iii/Cryptare/.github/workflows/cd.yml \
--source-ref refs/tags/v1.3.2
gh attestation verify oci://ghcr.io/jabbott-iii/cryptare:1.3.2 --repo jabbott-iii/Cryptare \
--signer-workflow jabbott-iii/Cryptare/.github/workflows/cd.yml \
--source-ref refs/tags/v1.3.2
Upgrading from v1.3.1
Everything v1.3.1 wrote still opens in v1.3.2. A few behaviours changed:
- Files encrypted with a stored key need v1.3.2 or later; v1.3.1 and earlier refuse them with “unsupported encrypted data: key source 2”. Upgrade every machine that needs to decrypt them.
keys exportnow takes the key’s master password rather than a separate export password. A script that passed a different export password fails with “wrong master password”, and a key whose master password is shorter than 15 characters can’t be exported; generate a new key instead.keys importchecks the key inside the export. An older export with its own password needs both passwords (see above).encrypt --key, anddecryptof a file encrypted with a stored key, open the key store; the other file commands still never touch it.- Failed commands no longer print the usage text after the error.
The full list, including notes for older versions, is in the README.
Security and quality
- CI checks that
go.modis tidy and that no key material is committed, runsgo vet, golangci-lint, and the full test suite on Linux, macOS, and Windows (with the race detector on Linux and macOS), and smoke-tests the built binary - CodeQL, gosec, and govulncheck run on every push and pull request, and weekly
- Third-party GitHub Actions are pinned by commit SHA and container base images by digest, and Dependabot keeps Go modules, actions, and base images current
- Every release ships with
checksums.txtand signed build provenance for each archive and the container image - Golden fixtures guard the on-disk formats, and fuzz tests cover the format parser, decryption, key exports, and archive extraction
- The container runs as an unprivileged user, and CI checks it
- Vulnerabilities can be reported privately through GitHub’s private vulnerability reporting, as described in SECURITY.md; security fixes ship as patch releases of the latest minor line
Get involved
Found a bug or have an idea for a feature? Please open an issue. Contributions are welcome. See CONTRIBUTING.md, and confirm the idea on an issue before opening a pull request.
Thank you for following along!