gocryptfs-standalone
v0.0.4
Published
Synchronizes a gocryptfs (plaintext names) encrypted directory with a decrypted copy without needing FUSE or admin rights.
Maintainers
Readme
Project Status
Use case
Work with a gocryptfs encrypted directory (for example synchronized via a cloud service like Google Drive) on machines where gocryptfs or a FUSE backend can not be installed (no admin rights). The tool runs as a standalone executable on Linux, macOS and Windows.
Only vaults created with gocryptfs -init -plaintextnames are supported
(feature flags HKDF GCMIV128 PlaintextNames). Every other vault is refused
so it never gets damaged.
Installation
Download the executable of your platform from the
releases
(linux, macos or windows, each for x64 and arm64), unpack it and
run it, no installation or admin rights needed. SHA256SUMS lists the
checksums of all archives.
The executables are not signed by a registered developer, so:
- macOS blocks downloaded ones at first: remove the quarantine flag with
xattr -d com.apple.quarantine gocryptfs-standalone-macos-*(or allow it under "System Settings → Privacy & Security"). - Windows SmartScreen may warn on first start ("More info → Run anyway").
- Linux executables need a glibc based distribution (not Alpine/musl).
With node (26 or newer) the package can be used directly as well:
npx gocryptfs-standalone ….
To build the executable of the current platform yourself:
yarn build:standalone (and yarn test:standalone to check it end to end).
Usage
gocryptfs-standalone init <vault> [--scryptn 16]
gocryptfs-standalone info <vault>
gocryptfs-standalone cat <vault> <path> > file
gocryptfs-standalone decrypt <vault> <target>
gocryptfs-standalone encrypt <source> <vault>
gocryptfs-standalone sync <plaintext> <vault> [--dry-run] [--trash-days 30]decrypt, encrypt and sync accept --exclude <pattern> (repeatable).
The vault's configuration file is looked up as gocryptfs.conf and then as
.gocryptfs.conf in the vault directory (init creates gocryptfs.conf).
Every command accepts --config <path> to use a configuration file located
elsewhere, like gocryptfs' -config option (for example to keep it out of
the cloud). Both names are reserved in the vault root and never synchronized.
decrypt and encrypt work one way: existing files on the target side get
overwritten, nothing gets deleted. Modification times, permissions and
symbolic links are carried over. Vaults created with init can be mounted
with gocryptfs (-init -plaintextnames compatible).
Synchronization
sync keeps a plaintext directory and a vault in sync in both directions.
After each run the state of both sides is remembered (a json file in the
user's configuration directory: %APPDATA%\gocryptfs-standalone on Windows,
$XDG_CONFIG_HOME/gocryptfs-standalone or ~/.config/gocryptfs-standalone
elsewhere). Compared to that state:
| Plaintext directory | Vault | Result |
| --- | --- | --- |
| changed / new | unchanged / missing | encrypted into the vault |
| unchanged / missing | changed / new | decrypted into the plaintext directory |
| deleted | unchanged | vault version moved into the trash |
| unchanged | deleted | plaintext version moved into the trash |
| changed | deleted | encrypted again (a change beats a deletion) |
| changed | changed | newer version wins, the older one is kept as name (conflict <host> <date>).ext on both sides |
Without a state (first run) both sides get merged, files existing on both
sides are compared by content, and nothing gets deleted. The trash lives
next to the state (pairs/<id>/trash, vault files stay encrypted there) and
gets purged after 30 days (--trash-days). Entries changing while being synchronized are
skipped and retried next time, a lock prevents parallel runs of the same
pair. --dry-run only shows what would happen.
Excludes
Excluded entries are left alone on both sides, as if they did not exist. Excluding something already synchronized never deletes it. Patterns follow gitignore conventions:
| Pattern | Matches |
| --- | --- |
| .DS_Store, *.tmp, ~$* | names at any depth |
| docs/*.pdf, docs/**/*.pdf | paths relative to the root |
| /build | only in the root |
| cache/, node_modules/ | only directories (with all their content) |
Supported globs: *, **, ?, [...] and {a,b}. Matching is case
insensitive on macOS and Windows.
Configured pairs and background synchronization
Pairs of a plaintext directory and a vault can be configured once and then be synchronized by name, all at once or periodically in the background:
# Asks for the password, verifies it and stores it in the keychain.
gocryptfs-standalone pair add documents ~/Documents/private ~/GoogleDrive/vault --interval 10m
gocryptfs-standalone pair list
gocryptfs-standalone sync documents # one pair
gocryptfs-standalone sync # all pairs
gocryptfs-standalone daemon # all pairs on changes and in their intervals until stopped
gocryptfs-standalone service install # start "daemon" after each log in
gocryptfs-standalone service status
gocryptfs-standalone service uninstall
gocryptfs-standalone pair remove documentsEverything lives in configuration.json inside the configuration directory
and can be edited by hand as well:
{
"defaults": {
"excludes": [".DS_Store", "._*", ".~lock.*#", "Thumbs.db", "desktop.ini", "~$*"],
"interval": "10m",
"trashDays": 30,
"watch": true
},
"pairs": {
"documents": {
"plaintext": "/home/me/Documents/private",
"vault": "/home/me/GoogleDrive/vault",
"interval": "5m",
"excludes": ["*.tmp", "build/"],
"trashDays": 7,
"watch": false,
"password": "keychain",
"config": "/home/me/vault.conf"
}
}
}A pair's excludes are added to the default ones. config is optional and
only needed for a configuration file outside of the vault (pair add
--config). Intervals take seconds,
minutes or hours (30s, 10m, 2h, at least 10 seconds). Password sources:
| Source | Meaning |
| --- | --- |
| "keychain" (default of pair add) | operating system's credential store, see below |
| "prompt" | asked interactively (once when the daemon starts) |
| "environment" | environment variable GOCRYPTFS_PASSWORD |
| {"file": "<path>"} | first line of the file (pair add --passfile) |
| {"command": "<command line>"} | first line of the output (pair add --extpass) |
Credential stores used without any native module or admin rights:
- macOS: login keychain via
security - Linux: Secret Service (GNOME Keyring, KWallet, …) via
secret-tool(packagelibsecret-toolsor similar) - Windows: DPAPI via PowerShell, the encrypted password is stored in
credentials/<pair>.dpapiinside the configuration directory and can only be decrypted by the same user on the same machine
The daemon unlocks all vaults on start (so wrong passwords fail early),
synchronizes every pair right away and afterwards in its interval. Runs never
overlap and failures get retried in the next interval, a run blocked by a
parallel sync of the same pair after 10 seconds. Only one daemon watches a
pair at a time, another one stops right away (exit code 4). Pairs must not
overlap: pair add, sync and daemon refuse configurations where a
directory of one pair (plaintext or vault) is located inside one of another
pair.
With "watch": true (default) the daemon additionally listens to file system
events of both sides (FSEvents on macOS, inotify on Linux, change
notifications on Windows) and synchronizes a pair 2 seconds after the last
change, at the latest 30 seconds after the first one while changes keep
coming. Changed entries still looking like after the last synchronization
(e.g. written by it) do not trigger a run. Events only trigger a regular
synchronization, so the interval stays
as fallback for changes no event reports: cloud clients (e.g. files arriving
in a Google Drive folder) and network or FUSE mounts often do not report
everything. If watching fails (e.g. Linux' limit of inotify watches,
fs.inotify.max_user_watches, is reached) the pair is synchronized in its
interval only and watching is retried every 5 minutes. --no-watch disables
watching for pair add or a single daemon run. service install
registers it per user:
- macOS: launchd agent
~/Library/LaunchAgents/com.tsickert.gocryptfs-standalone.plist, logging todaemon.login the configuration directory - Linux: systemd user unit
~/.config/systemd/user/gocryptfs-standalone.service(log:journalctl --user -u gocryptfs-standalone, keep it running while logged out withloginctl enable-linger) - Windows: command file in the user's startup folder, starting the daemon
minimized and logging to
daemon.login the configuration directory
Password of single commands
The password is taken from the first available source:
--passfile <path>(first line of the file)--extpass <command>(first line of the command's output)- Environment variable
GOCRYPTFS_PASSWORD - Interactive prompt
Alternatively --masterkey <hex> unlocks the vault with its master key. A
given master key is checked against existing vault content before anything
gets encrypted with it.
Related projects
- gocryptfs defines the on-disk format implemented here.
- gocryptfs-inspect and gocryptfs-create-folder are Python tools decrypting files respectively creating vaults without FUSE.
