GPG
GnuPG key management, signing, encryption, and web of trust operations.
Key Generation
Generate a new GPG key pair — ed25519 is preferred over RSA for new keys
gpg --full-generate-key
Select ECC (sign and encrypt) > Curve 25519 > set expiry (2y recommended). Never create keys without expiry.
Generate non-interactively — scripted key generation
gpg --batch --gen-key <<'EOF'
Key-Type: eddsa
Key-Curve: ed25519
Key-Usage: sign
Subkey-Type: ecdh
Subkey-Curve: cv25519
Subkey-Usage: encrypt
Name-Real: Evan
Name-Email: evan@domusdigitalis.dev
Expire-Date: 2y
%no-protection
%commit
EOF
Key Management
List public keys
gpg --list-keys --keyid-format long
List secret (private) keys
gpg --list-secret-keys --keyid-format long
Export public key — safe to share
gpg --armor --export evan@domusdigitalis.dev > evan-public.asc
Export private key — guard with your life
gpg --armor --export-secret-keys evan@domusdigitalis.dev > evan-private.asc
Private key export creates an unprotected copy. Encrypt it immediately with age or store in a hardware token.
|
Import a public key
gpg --import colleague-public.asc
Import a private key (restore from backup)
gpg --import evan-private.asc
Delete a public key
gpg --delete-keys KEYID
Delete a secret key (must delete secret before public)
gpg --delete-secret-keys KEYID
gpg --delete-keys KEYID
Key Fingerprint & Trust
Show full fingerprint — verify out-of-band before trusting
gpg --fingerprint evan@domusdigitalis.dev
Set trust level on an imported key
gpg --edit-key colleague@example.com trust
Trust levels: 1=unknown, 2=never trust, 3=marginally, 4=fully, 5=ultimately. Only set 5 (ultimate) for your own keys.
Sign someone’s key — vouch for their identity
gpg --sign-key colleague@example.com
Encrypt & Decrypt
Encrypt for a recipient — ASCII-armored output
gpg --armor --encrypt --recipient evan@domusdigitalis.dev document.txt
Encrypt for multiple recipients
gpg --armor --encrypt \
--recipient evan@domusdigitalis.dev \
--recipient colleague@example.com \
document.txt
Decrypt a file
gpg --decrypt document.txt.asc > document.txt
Decrypt to stdout — pipe without touching disk
gpg --decrypt --quiet secrets.gpg | jq '.api_key'
Sign & Verify
Sign a file — creates detached signature
gpg --armor --detach-sign release.tar.gz
Verify a detached signature
gpg --verify release.tar.gz.asc release.tar.gz
Clearsign — embed signature in plaintext (for emails, announcements)
gpg --clearsign announcement.txt
Git Commit Signing
Configure git to sign commits with your GPG key
# Get your signing key ID
gpg --list-secret-keys --keyid-format long | awk '/^sec/{print $2}' | cut -d/ -f2
# Configure git
git config --global user.signingkey KEYID
git config --global commit.gpgsign true
git config --global tag.gpgsign true
Verify signed commits in a repo
git log --show-signature -5
Tell GitHub about your key — export and paste in Settings > SSH and GPG keys
gpg --armor --export evan@domusdigitalis.dev | xclip -selection clipboard
Key Servers
Upload your public key to a keyserver
gpg --keyserver hkps://keys.openpgp.org --send-keys KEYID
Search for a key on a keyserver
gpg --keyserver hkps://keys.openpgp.org --search-keys colleague@example.com
Receive (download) a key by ID
gpg --keyserver hkps://keys.openpgp.org --recv-keys KEYID
Refresh keys — pull updates (revocations, new subkeys)
gpg --keyserver hkps://keys.openpgp.org --refresh-keys
Key Revocation
Generate a revocation certificate — do this immediately after key creation
gpg --gen-revoke --armor --output revoke-evan.asc evan@domusdigitalis.dev
Store revoke-evan.asc offline (USB, printed). If your key is compromised, import it to revoke:
Revoke a compromised key
gpg --import revoke-evan.asc
gpg --keyserver hkps://keys.openpgp.org --send-keys KEYID
GPG Agent
Restart the agent (fixes "no secret key" errors)
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
Set cache TTL in ~/.gnupg/gpg-agent.conf
default-cache-ttl 3600 max-cache-ttl 86400