GPG (GNU Privacy Guard) encryption lets you protect files, sign documents, verify software authenticity, and prove your identity in Git commits — all using public-key cryptography that does not require sharing a secret password. When you send an encrypted file, only the intended recipient with their private key can decrypt it. When you sign a Git commit, anyone can verify that you wrote it and that the code has not been tampered with. This guide covers practical GPG usage from key generation through everyday workflows for file encryption, digital signatures, and Git integration.
Prerequisites
- A Linux, macOS, or Windows system
- GnuPG 2.2 or later installed (check with
gpg --version) - A terminal or command prompt
- An email address for your key identity
Installing GnuPG
# Debian / Ubuntu (usually pre-installed)
sudo apt install gnupg
# RHEL / Fedora
sudo dnf install gnupg2
# macOS
brew install gnupg
# Verify installation
gpg --version
# gpg (GnuPG) 2.4.x
Generating Your Key Pair
# Interactive key generation with full options
gpg --full-generate-key
When prompted:
- Key type: Choose
ECC (sign and encrypt)orRSA and RSAfor broadest compatibility - Key size: 4096 for RSA, or
Curve 25519for ECC - Expiration: Set 1-2 years (you can extend it later). Never create keys without expiration
- Name and email: Use the same email as your Git and GitHub account
- Passphrase: Use a strong passphrase — this protects your private key if the file is stolen
# List your keys
gpg --list-keys
gpg --list-secret-keys --keyid-format long
# Output example:
# sec ed25519/ABC123DEF456 2025-12-12 [SC] [expires: 2027-12-12]
# ABCDEF1234567890ABCDEF1234567890ABC123DE
# uid [ultimate] Your Name <you@example.com>
# ssb cv25519/789GHI012JKL 2025-12-12 [E] [expires: 2027-12-12]
The key ID (ABC123DEF456 in this example) is what you use to reference your key in commands.
Generate a Revocation Certificate
Do this immediately after creating your key — before you need it:
gpg --gen-revoke --output revoke-cert.asc ABC123DEF456
Store this file securely offline (USB drive, printed paper). If your key is compromised, you publish this certificate to revoke it.
Encrypting and Decrypting Files
Encrypt for a Recipient (Asymmetric)
# First, import the recipient's public key
gpg --import colleague-pubkey.asc
# Encrypt a file for a specific recipient
gpg --encrypt --recipient colleague@example.com secret-report.pdf
# Creates: secret-report.pdf.gpg
# Encrypt for multiple recipients
gpg --encrypt --recipient alice@example.com --recipient bob@example.com data.tar.gz
# Encrypt and sign (recommended — proves who sent it)
gpg --encrypt --sign --recipient colleague@example.com secret-report.pdf
# Encrypt with ASCII armor (text-safe output for email)
gpg --encrypt --armor --recipient colleague@example.com message.txt
# Creates: message.txt.asc (base64-encoded, safe for email)
Decrypt a File
# Decrypt (GPG automatically uses your private key)
gpg --decrypt secret-report.pdf.gpg > secret-report.pdf
# Decrypt and verify signature
gpg --decrypt signed-encrypted-file.gpg
# Output includes: "Good signature from ..."
Symmetric Encryption (Password-Based)
When you do not have the recipient’s public key, use a shared password:
# Encrypt with a passphrase (no keys needed)
gpg --symmetric --cipher-algo AES256 backup.tar.gz
# Prompts for a passphrase
# Creates: backup.tar.gz.gpg
# Decrypt
gpg --decrypt backup.tar.gz.gpg > backup.tar.gz
Signing Files and Messages
Digital signatures prove authenticity (who signed it) and integrity (the content has not changed).
# Create a detached signature (separate .sig file)
gpg --detach-sign release-v1.0.tar.gz
# Creates: release-v1.0.tar.gz.sig
# Verify a detached signature
gpg --verify release-v1.0.tar.gz.sig release-v1.0.tar.gz
# Good signature from "Your Name <you@example.com>"
# Create a cleartext signature (human-readable)
gpg --clearsign announcement.txt
# Creates: announcement.txt.asc (text with embedded signature)
# Verify a cleartext signature
gpg --verify announcement.txt.asc
Git Commit Signing
Signed commits show a “Verified” badge on GitHub and GitLab, proving you authored the commit.
Setup
# Find your GPG key ID
gpg --list-secret-keys --keyid-format long
# sec ed25519/ABC123DEF456 2025-12-12 [SC]
# Configure Git to use your key
git config --global user.signingkey ABC123DEF456
# Enable automatic signing for all commits
git config --global commit.gpgsign true
# Also sign tags
git config --global tag.gpgsign true
# If GPG prompts fail, set the TTY
export GPG_TTY=$(tty)
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
Export Your Public Key to GitHub/GitLab
# Export your public key in ASCII format
gpg --export --armor ABC123DEF456
# Copy the output (including -----BEGIN PGP PUBLIC KEY BLOCK-----)
# Paste it in GitHub: Settings > SSH and GPG keys > New GPG key
Signing in Practice
# Sign a single commit
git commit -S -m "Fix authentication bug"
# Verify signatures in the log
git log --show-signature -3
# Sign a tag
git tag -s v1.0 -m "Release 1.0"
# Verify a signed tag
git tag -v v1.0
Comparing Encryption Tools
| Feature | GPG (GnuPG) | age | OpenSSL | Signal Protocol |
|---|---|---|---|---|
| Use case | Files, email, Git | File encryption | TLS, certificates, files | Messaging |
| Key management | Keyring, key servers | Simple key files | Certificates, CAs | Automatic |
| Complexity | High (many options) | Very low | Moderate | Built-in to apps |
| Asymmetric encryption | Yes (RSA, ECC) | Yes (X25519) | Yes | Yes |
| Digital signatures | Yes | No | Yes | Yes |
| Git integration | Native | No | No | No |
| Best for | Email, Git, package signing | Simple file encryption | TLS/server security | Chat applications |
Use GPG for Git commit signing, email encryption, and verifying software packages. Use age when you need simple file encryption without the complexity of key management. Use OpenSSL for TLS certificates and server-side encryption.
Key Management Best Practices
# Export your private key for backup (store offline!)
gpg --export-secret-keys --armor ABC123DEF456 > private-key-backup.asc
# Export your public key
gpg --export --armor ABC123DEF456 > public-key.asc
# Import a key from a file
gpg --import someone-public-key.asc
# Import from a key server
gpg --keyserver keyserver.ubuntu.com --recv-keys THEIR_KEY_ID
# Upload your key to a key server
gpg --keyserver keyserver.ubuntu.com --send-keys ABC123DEF456
# Extend key expiration before it expires
gpg --edit-key ABC123DEF456
# gpg> expire
# (set new expiration)
# gpg> save
# Revoke a compromised key
gpg --import revoke-cert.asc
gpg --keyserver keyserver.ubuntu.com --send-keys ABC123DEF456
Gotchas and Edge Cases
Expired keys cannot encrypt or sign: If your key expires, you cannot create new signatures or encrypt data for recipients. You can still decrypt old data and extend the expiration date from the private key. Always extend before expiration.
Trust model confusion: Importing someone’s public key does not mean you trust it. GPG marks untrusted keys with a warning. Use gpg --edit-key THEIR_ID and trust to set the trust level, or sign their key with lsign after verifying their identity.
SSH agent vs GPG agent: GPG has its own agent (gpg-agent) that caches your passphrase. If you also use an SSH agent, they can conflict. Modern GPG can serve as an SSH agent too — configure this in ~/.gnupg/gpg-agent.conf with enable-ssh-support.
GUI passphrase prompts in headless sessions: When running GPG over SSH or in scripts, the pinentry program may fail because there is no GUI. Set GPG_TTY=$(tty) and configure pinentry-curses in ~/.gnupg/gpg-agent.conf:
echo "pinentry-program /usr/bin/pinentry-curses" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Large file encryption is slow: GPG is not designed for encrypting multi-gigabyte files. For large data, encrypt with a symmetric cipher (AES256) and protect the passphrase with GPG, or use tools like age that are optimized for file encryption.
Troubleshooting
”gpg: signing failed: No secret key"
# Check that the signing key ID matches your Git config
git config --global user.signingkey
gpg --list-secret-keys --keyid-format long
# Ensure the email in your GPG key matches your Git email
git config --global user.email
"gpg: decryption failed: No secret key”
# You need the private key that matches the encryption recipient
gpg --list-secret-keys
# If the key is on another machine, export and import it
# On the source machine:
gpg --export-secret-keys --armor KEYID > key.asc
# On the target machine:
gpg --import key.asc
Git commit signing hangs
# The GPG agent cannot prompt for passphrase
export GPG_TTY=$(tty)
# Test GPG signing directly
echo "test" | gpg --clearsign
# If using VS Code or IDE, configure the TTY in your shell profile
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
Summary
- GPG uses public-key cryptography where your public key encrypts data and your private key decrypts it — share public keys freely, protect private keys absolutely
- Generate keys with
gpg --full-generate-keyand immediately create a revocation certificate stored offline for emergency key revocation - Encrypt files with
gpg --encrypt --recipientfor asymmetric encryption, orgpg --symmetricwhen sharing a passphrase is simpler - Sign Git commits with
git commit -Sand configurecommit.gpgsign truefor automatic signing — add your public key to GitHub for “Verified” badges - Set key expiration dates and extend them before they expire — an expired key blocks encryption and signing but still decrypts old data
- Back up your private key to offline storage — losing it means permanent loss of decryption ability for all data encrypted to that key