Security¶
Two independent layers: the vault encrypts everything at
rest, and OpenPGP signs and encrypts individual messages.
Both drive tools you already run (hdiutil, cryptsetup,
gocryptfs, gpg-agent); Antiphon never handles secret key
material itself.
The vault¶
The store at $XDG_DATA_HOME/antiphon/store holds your Maildir,
notmuch index, OAuth tokens and account state. With a vault, it
is ciphertext on disk when locked and decrypted in place only
while the daemon runs. A backup tool copying a locked store
copies ciphertext.
antiphon doctor # says whether the store is a vault or plain
Choose a backend¶
[vault]
backend = "auto" # auto picks the right one per platform
| Backend | Platform | Notes |
|---|---|---|
apfs |
macOS | Encrypted APFS sparse image via hdiutil, AES-256, no admin rights |
luks2 |
Linux | LUKS2 via cryptsetup; open/mount use a narrow sudo allowance |
gocryptfs |
any | FUSE, rootless, the portable fallback |
Set it up¶
# set backend and passphrase_cmd in [vault] first, then:
antiphon vault create # create and mount the vault
antiphon doctor --init-store # lay out the store inside it
antiphond & # unlocks on start, seals on stop
antiphon
antiphon vault create will not shadow an existing plain store.
To migrate one, move it aside, create the vault, then copy the
mail back in while the vault is mounted.
Unlock with a passphrase¶
Every vault has a passphrase, and it always works. The daemon
reads it from passphrase_cmd, a command that prints the
secret; the passphrase itself is never stored in config.
[vault]
backend = "auto"
passphrase_cmd = "pass show antiphon/vault"
idle_lock_minutes = 30 # 0 = stay open until the daemon stops
Any secret-printing command works:
pass show antiphon/vault
secret-tool lookup service antiphon-vault
security find-generic-password -w -s antiphon-vault # macOS
antiphon setup creates that macOS Keychain item for you. With
idle_lock_minutes above zero the vault seals after that many
minutes without a connected client, and reopens when a client
next connects.
Unlock with a hardware token¶
Beyond the passphrase, a hardware token can open the vault. On
macOS, antiphon vault touchid-enrol stores the passphrase
behind a Touch ID Keychain item. On any platform, antiphon
vault yubikey-enrol seals it under a YubiKey's FIDO2
hmac-secret: enrol a primary and a backup key, and whichever is
present opens the vault with a single touch.
antiphon vault touchid-enrol # macOS Touch ID
antiphon vault yubikey-enrol # FIDO2 YubiKey (run once per key)
List the methods to try, in order, and give the YubiKey's PIN its own command:
[vault]
unlock = ["touchid", "yubikey", "passphrase"]
yubikey_pin_cmd = "pass show antiphon/yubikey-pin"
A hardware method that is cancelled, absent or wrong falls through to the next, and finally to the passphrase, never past the vault.
OpenPGP¶
Verification runs in the client (pure Rust). Signing and decryption are handed to your running gpg-agent, so your keyring, smartcard and pinentry behave exactly as elsewhere.
Verify signatures¶
Antiphon trusts only the certificates you place in
$XDG_CONFIG_HOME/antiphon/pgp/. Add a correspondent's key:
gpg --armor --export alice@example.com \
> ~/.config/antiphon/pgp/alice.asc
The pager then shows Good signature from … for a message that
verifies against a cert there, Unknown signature for a signer
you have not added, and BAD signature when a trusted key
matches but the content does not. PGP/MIME and inline signatures
are both handled. There is no web-of-trust or TOFU: a cert is
trusted because you put it there.
Sign and encrypt¶
Turn signing on per identity in the account file:
[[identity]]
address = "you@example.com"
pgp_sign = true
pgp_key = "0xFINGERPRINT" # optional; pins a specific key
Override the default for the next message only:
:sign :nosign :encrypt :noencrypt
The compose status line shows the live plan. Sealing happens through gpg-agent when the editor closes, so pinentry or a smartcard touch appears as usual. Encryption needs a cert for every To and Cc address; if one is missing or refused the message aborts to a draft naming the problem rather than sending plaintext. Received encrypted mail decrypts through the agent when opened.
antiphon doctor # keyring size, gpg-agent reachability, key count
Long-term archives¶
The vault protects the store in place. Mail you deliberately
keep as a long-term archive is protected by age instead:
antiphon export writes an age-encrypted archive and antiphon
view reads it back without the account. See
export and archives.