gpg — OpenPGP encryption, signing, and key management — GnuPG across all 5 shells
Equivalents in every shell
gpg --encrypt --recipient RECIPIENT-KEY-ID fileGnuPG (the OpenPGP implementation). On most distros installs as `gnupg` or `gnupg2`; binary is `gpg`. Operates on the keyring under `~/.gnupg/`. `gpg-agent` caches passphrases and brokers smartcard / YubiKey access via `pinentry`. Cleartext output of `--decrypt` goes to stdout — pipe to a file or use `-o`. The `--recipient` value can be any user-ID substring, a key-ID (`0xDEADBEEF`), or a full fingerprint — pick a unique fingerprint to avoid ambiguity in production scripts.
gpg --encrypt --recipient RECIPIENT-KEY-ID fileSame external binary. macOS ships nothing — install via `brew install gnupg` (CLI only) or GPG Suite (GUI + Apple Mail integration). Homebrew installs include `pinentry-mac` for a native passphrase prompt window.
gpg --encrypt --recipient RECIPIENT-KEY-ID fileSame external. Fish ships completion for common subcommands. To bridge `gpg-agent` as the SSH agent in fish: `set -gx SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)` and enable `enable-ssh-support` in `~/.gnupg/gpg-agent.conf`.
gpg.exe --encrypt --recipient RECIPIENT-KEY-ID filePowerShell has NO built-in OpenPGP. Install Gpg4win (`choco install gpg4win` / `winget install GnuPG.Gpg4win`) for `gpg.exe`. The built-in `Protect-CmsMessage` / `Unprotect-CmsMessage` cmdlets use X.509 / S/MIME — a DIFFERENT standard, INCOMPATIBLE with OpenPGP messages.
gpg.exe --encrypt --recipient RECIPIENT-KEY-ID fileSame Gpg4win binary. No native OpenPGP. cmd cannot decrypt anything OpenPGP-encrypted by a Unix peer without Gpg4win installed. Sysinternals does not include a gpg client.
Worked examples
Encrypt a file for one recipient with ASCII-armored output
gpg --encrypt --armor --recipient 0xDEADBEEF secret.txtgpg --encrypt --armor --recipient 0xDEADBEEF secret.txtgpg.exe --encrypt --armor --recipient 0xDEADBEEF secret.txtDecrypt a file (agent prompts for the private-key passphrase)
gpg --decrypt secret.txt.asc > secret.txtgpg.exe --decrypt secret.txt.asc | Set-Content secret.txt -Encoding UTF8Sign a release tarball with a detached signature
gpg --detach-sign --armor release-1.2.3.tar.gzgpg.exe --detach-sign --armor release-1.2.3.tar.gzGotchas
- OpenPGP (`gpg`) and S/MIME (PowerShell `Protect-CmsMessage`, `openssl smime`) are different standards with incompatible message formats. A file encrypted with `gpg --encrypt` cannot be decrypted by `Unprotect-CmsMessage` — those use X.509 certificates while GPG uses OpenPGP keys.
- Smartcards / YubiKeys go through `pinentry`. Scripts run by cron / systemd / a CI runner often have no TTY to prompt on — set `pinentry-mode loopback` and pass the PIN via `--passphrase-fd 0`, or use a passphrase-less subkey for unattended signing. Confirm card state with `gpg --card-status`.
- Windows has NO built-in OpenPGP — Gpg4win is the de-facto stack. Cross-platform CI that signs both Unix and Windows artefacts should install Gpg4win on the Windows runner, not roll its own encryption layer. The PowerShell `Get-CmsMessage` / `Protect-CmsMessage` family are S/MIME-only and cannot read OpenPGP.
- Inside WSL the Linux `gpg-agent` is INDEPENDENT from a Windows-side Gpg4win agent — same key file on `/mnt/c` does NOT mean a shared agent session. To forward the Linux `gpg-agent` socket (`~/.gnupg/S.gpg-agent.extra`) into Windows-side SSH use, bridge with `weasel-pageant` or import the key into both keyrings.
- `gpg --gen-key` defaults differ by version. Modern GnuPG 2.2+ generates RSA-3072 with a 2-year expiry; older 2.0 generated RSA-2048 with no expiry. For reproducible provisioning use `gpg --quick-generate-key 'Name <email>' ed25519 cert,sign 2y` so the key shape is fixed regardless of the host's default.