- Zig 85.7%
- JavaScript 8.5%
- CSS 1.9%
- HTML 1.5%
- Nix 1.4%
- Other 1%
| extension/chrome | ||
| native-messaging/chrome | ||
| src | ||
| tools | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| TODO.md | ||
pak
pak is a small Zig password manager prototype backed by SQLite. It stores
named secrets encrypted with ChaCha20-Poly1305. The master password is stretched
with Argon2id, and every vault stores an encrypted verifier so wrong passwords
can be rejected before decrypting any saved secret.
This is a prototype, not a security audit.
Development
nix develop
zig build
zig build test
The default vault path is pak.db. Use -v or --path to target another file.
Website
Build the static website and release binaries:
zig build website
The output is written to zig-out/site, with compiled release binaries in
zig-out/site/releases.
Deploy the generated site with rsync:
zig build deploy-website -Dwebsite-dest='user@host:/srv/www/pak/'
Create A Vault
Create a new vault:
pak init -p 'MASTER_PASSWORD'
Create a vault at a specific path:
pak init -v work.db -p 'MASTER_PASSWORD'
init creates the SQLite database, stores the key-derivation salt, and writes an
encrypted verifier record.
Verify A Vault Password
pak open -p 'MASTER_PASSWORD'
pak open -v work.db -p 'MASTER_PASSWORD'
On success:
verifier: ok
opened
With a wrong password, the verifier fails and no secrets are decrypted.
Store Secrets
Set or replace a secret:
pak set -n github-token -s 'ghp_secret' -p 'MASTER_PASSWORD'
pak set -v work.db -n deploy-key -s 'secret text' -p 'MASTER_PASSWORD'
Secret names are stored in plaintext so they can be listed without unlocking the vault. Secret values are encrypted. The secret name is included in the AEAD AAD, so moving encrypted payloads between names fails authentication.
Read Secrets
Get one secret value:
pak get -n github-token -p 'MASTER_PASSWORD'
pak get -v work.db -n deploy-key -p 'MASTER_PASSWORD'
If the name does not exist, pak reports that the secret was not found.
List Secrets
List secret names without unlocking values:
pak list
pak list -v work.db
pak vault is an alias for the same list operation:
pak vault
Pass a password source to include decrypted values:
pak list -p 'MASTER_PASSWORD'
pak vault -v work.db -p 'MASTER_PASSWORD'
Output with values is tab-separated:
github-token ghp_secret
deploy-key secret text
macOS Keychain Passwords
Instead of passing -p, pak can read the master password from the macOS
Keychain with -k or --keychain.
By default, it looks up:
service: pak
account: <vault path>
For the default pak.db vault, store the password like this:
security add-generic-password -s pak -a pak.db -w 'MASTER_PASSWORD' -U
Then use:
pak open --keychain
pak set -n github-token -s 'ghp_secret' -k
pak get -n github-token -k
pak list -k
For a custom vault path:
security add-generic-password -s pak -a work.db -w 'MASTER_PASSWORD' -U
pak get -v work.db -n deploy-key -k
You can override the Keychain service and account:
pak get -n github-token --keychain \
--keychain-service pak \
--keychain-account pak.db
If -p/--password is provided, it takes precedence over -k/--keychain.
Chrome Browser Integration
The repository includes a Chrome extension and a Native Messaging host.
Build the CLI and host binary:
zig build
Load the extension from extension/chrome with Chrome's "Load unpacked" button,
then copy the generated extension ID from chrome://extensions.
Register the native host for that extension ID:
native-messaging/chrome/install-host.sh CHROME_EXTENSION_ID
By default the installer points Chrome at zig-out/bin/pak-native-host. Pass a
second argument to use another installed host path:
native-messaging/chrome/install-host.sh CHROME_EXTENSION_ID /usr/local/bin/pak-native-host
The extension talks to pak-native-host over Chrome Native Messaging using
length-prefixed JSON. The host currently keeps the unlocked vault in its own
process while Chrome holds the native messaging port open. The protocol is
intentionally small: status, unlock, lock, list, get, and set.
Command Reference
The block below is generated from the same usage text printed by pak --help.
Run zig build update-readme to refresh it.
pak - encrypted SQLite secret vault
Usage:
pak init [-v PATH] (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
pak open [-v PATH] (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
pak set [-v PATH] -n NAME -s SECRET (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
pak get [-v PATH] -n NAME (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
pak list [-v PATH] [(-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])]
pak vault [-v PATH] [(-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])]
Commands:
init Create a new vault database and verifier record.
open Verify that the master password unlocks the vault.
set Create or replace an encrypted named secret.
get Decrypt and print one named secret.
list List secret names. With a password source, include values.
vault Alias for list.
Options:
-v, --path PATH Vault database path. Defaults to pak.db.
-p, --password PASSWORD Master password. Takes precedence over -k/--keychain.
-n, --name NAME Secret name for get/set.
-s, --secret SECRET Secret value for set.
-k, --keychain Read master password from macOS Keychain.
--keychain-service S Keychain service. Defaults to pak.
--keychain-account A Keychain account. Defaults to the vault path.
--help Show this help.
Examples:
pak init -p 'MASTER_PASSWORD'
pak set -n github-token -s 'ghp_secret' -p 'MASTER_PASSWORD'
pak get -n github-token -p 'MASTER_PASSWORD'
pak list
pak list -p 'MASTER_PASSWORD'
security add-generic-password -s pak -a pak.db -w 'MASTER_PASSWORD' -U
pak get -n github-token -k
Notes
The current CLI is intentionally simple. Passwords passed with -p can be
visible through shell history or process listings; prefer -k/--keychain for local
interactive use. Decrypted values are printed to stdout by get and by
list/vault when a password source is provided.