cheat-sheets

GPG

GnuPG implements OpenPGP: public-key encryption, signatures and symmetric encryption for files, email, Git commits and package repositories. For SSH keys see OpenSSH Cheat-Sheet; for X.509 certificates see OpenSSL. For encrypting secrets in a repo, SOPS and age is usually simpler.

Documentation: GnuPG Manual

Keys #

COMMANDDESCRIPTION
gpg --full-generate-keyInteractive key generation
gpg --quick-generate-key "Name <mail@example.com>" ed25519 cert neverCreate a certify-only primary key
gpg --quick-add-key <FPR> ed25519 sign 2yAdd a signing subkey (expires in 2 years)
gpg --quick-add-key <FPR> cv25519 encr 2yAdd an encryption subkey
gpg --quick-set-expire <FPR> 2yChange the primary key expiry
gpg --list-keys --keyid-format longList public keys
gpg --list-secret-keys --keyid-format longList secret keys (sec# means primary key is offline)
gpg --fingerprint <KEYID>Show the fingerprint
gpg --edit-key <KEYID>Interactive menu (trust, adduid, expire, addkey, save)
gpg --delete-secret-and-public-key <FPR>Remove a key pair
gpg --import key.ascImport a key
gpg --keyserver keys.openpgp.org --search-keys <MAIL>Search a keyserver
gpg --keyserver keys.openpgp.org --send-keys <FPR>Upload a public key

keys.openpgp.org only publishes a user ID after the owner verifies the email address. Never upload a secret key.

A good layout: an offline certify-only primary key, plus separate subkeys for signing, encryption and authentication. A stolen subkey can be revoked without losing your identity.

Encrypt and Decrypt #

COMMANDDESCRIPTION
gpg -e -r <MAIL> fileEncrypt to a recipient (writes file.gpg)
gpg -e -a -r <MAIL> fileASCII-armoured output (file.asc)
gpg -c fileSymmetric encryption with a passphrase
gpg -c --cipher-algo AES256 fileChoose the cipher
gpg -d file.gpg > fileDecrypt to stdout
gpg -o file -d file.gpgDecrypt to a file
gpg -e -r <A> -r <B> fileEncrypt to several recipients

Sign and Verify #

COMMANDDESCRIPTION
gpg --detach-sign -a fileDetached ASCII signature (file.asc)
gpg --verify file.asc fileVerify a detached signature
gpg --clearsign fileCleartext signature (file.asc)
gpg -s fileSigned (not encrypted) binary wrapper
gpg --verify file.sigVerify an embedded signature
gpg -u <KEYID> --detach-sign fileSign with a specific key

Backup and Restore #

COMMANDDESCRIPTION
gpg --export -a <FPR> > public.ascExport the public key
gpg --export-secret-keys -a <FPR> > secret.ascExport the primary and all secret subkeys
gpg --export-secret-subkeys -a <FPR> > subkeys.ascExport subkeys only (primary key stays out)
gpg --export-ownertrust > trust.txtExport trust settings
gpg --import-ownertrust trust.txtRestore trust settings
gpg --gen-revoke -a -o revoke.asc <FPR>Pre-generate a revocation certificate
gpg --import revoke.ascApply a revocation certificate

Generate the revocation certificate straight after creating the key and store it with the backup. Keep exported secret keys on encrypted offline media (and a copy in Bitwarden Cheat-Sheet); delete them from the machine afterwards.

Moving subkeys to a daily-use machine while the primary stays offline:

bash
gpg --export-secret-subkeys -a <FPR> > subkeys.asc
# on the daily machine
gpg --import subkeys.asc
gpg --list-secret-keys          # primary shows as sec# (stub)

Git Commit Signing #

bash
git config --global user.signingkey <KEYID>
git config --global commit.gpgsign true
git config --global tag.gpgsign true
gpg --armor --export <KEYID>     # paste into GitHub > Settings > SSH and GPG keys

Git can also sign with an SSH key (gpg.format ssh); see Git.

Agent and Passphrase #

COMMANDDESCRIPTION
export GPG_TTY=$(tty)Needed in shells so pinentry can prompt (add to ~/.bashrc or ~/.zshrc)
gpgconf --kill gpg-agentRestart the agent (fixes most stuck states)
gpgconf --list-dirsShow agent socket and home paths
gpg --pinentry-mode loopback -d file.gpgPrompt on the terminal instead of a GUI
gpg --batch --pinentry-mode loopback --passphrase-file <FILE> -d file.gpgNon-interactive decrypt (protect the file)

~/.gnupg/gpg-agent.conf example:

text
default-cache-ttl 600
max-cache-ttl 7200
pinentry-program /usr/bin/pinentry-curses

Troubleshooting #

SYMPTOMFIX
gpg: signing failed: Inappropriate ioctl for deviceexport GPG_TTY=$(tty)
gpg: decryption failed: No secret keyKey not imported on this machine, or only the subkey stub exists
gpg: WARNING: This key is not certified with a trusted signatureCosmetic. Run gpg --edit-key <ID>, then trust, if you’ve verified the fingerprint
gpg: signing failed: No secret key after moving to subkeysEnsure a signing-capable subkey exists and isn’t expired
Key expiredgpg --edit-key <ID>, expire, key 1, expire, save — then re-publish the public key
Agent hangs or can't connect to the agentgpgconf --kill gpg-agent and retry
Permissions warningschmod 700 ~/.gnupg && chmod 600 ~/.gnupg/*
Search all sheets

Tip: / or Ctrl/Cmd+K to open, Esc to close.