GNU Privacy Guard is very powerful software with a terrible interface.
This document attempts to give you the tools needed to answer questions and explain the mysteries of gpg and PGP so that you too can take advantage of this tool and stop making excuses.
This page assumes you have basic familiarity with
gpg and have already created an OpenPGP key. If not, please see Secure PGP keys and Yubikey NEO.md for information on how to create an offline master key and then transfer the sub keys onto a YubiKey hardware device for daily use.
- Example config file (
~/.gnupg/gpg.conf) - Some better defaults.
- My key signing policy - to learn about different signature types and what they mean to me.
Web Of Trust
The OpenPGP Web Of Trust is a way to establish the authenticity of the binding between a public key and its owner without relying on centralized authorities. Participants can chose to verify, then sign each other's keys, then publish those signatures for other people to use. Once your key is in the "Strong Set" (set of cross-signed keys), anyone can use a tool such as the PGP pathfinder to easily calculate trust paths from one key to another (modern software will do this automatically). This can be especially helpful when verifying digital signatures on software for example.
"Signing" someone's key means that you use your Master key's
C (Certify) capability to make a digital signature on one or more ID's of their public key. This indicates to what degree you verified the data in that specific UID (usually name and email address). Ideally the checking should be done in-person, government issued ID should be compared to the name listed in the key UID, and the key fingerprint should be provided by the owner on paper to be taken home and verified + signed later.
Here are slides from a presentation that I did on the OpenPGP Web Of Trust with visual examples.
Signing keys offline
Signing another person's key with your "offline" master key is far more secure than keeping the master key on a normal Internet-connected computer. It is also a bit more complex, but instructions below should easily guide you through the process. Replace
KEYID below with the actual long ID of the key you want to sign:
- Locate the key you want to sign, eg:
gpg --search KEYID. Then type the number of the key you want to import into Gnupg's database.
- Check the master key fingerprint, eg:
gpg --fingerprint KEYID
- When satisfied, export the public key to a file, eg:
gpg -a --export KEYID > KEYID_unsigned.asc
- Put the key you want to sign onto a clean USB stick (or find some other way to get it into your air-gapped computer).
- Enter your air-gapped environment (eg, boot into TailsOS).
- Import your current Secret key (aka Master key) to the air-gapped machine.
- Check your key is available with:
gpg -K(big 'K') or
- Import the public key to be signed:
gpg --import KEYID_unsigned.asc
- Sign the person's public key:
gpg --ask-cert-level --sign-key KEYID
- You will be prompted to specify which IDs you want to sign and asked how thoroughly you checked the identity info. Here is a copy of my key signing policy which might be helpful place to start.
- I recommend signing all IDs here (default) and later deleting any signatures you don't want to send.
- Export the signed key as a file:
gpg -a --export KEYID > KEYID_signed.asc
- Transport that signed key file back from the air-gapped machine to the online system.
- Import the signed key:
gpg --import KEYID_signed.asc
- Verify your signature on their key:
gpg --check-sigs KEYID
- Finalize the verification process by emailing the signature to the owner (below).
Ensuring that your signature goes to the right UID
It is tempting to just upload the key directly to a keyserver, but this is considered bad form because the data you signed is not verified and uploading irrevocably publishes data that the user may not want to make public (see section below about what can be changed on a keyserver).
Instead, we will send each signed UID to the email address listed in an encrypted email.
This ensures that:
- They still control that email address. (can read the email)
- They control the private key for the public key you are signing. (can decrypt the message)
If there is only 1 email address listed in the key, then this is easy -- just send the
KEYID_signed.asc file to the email address listed (encrypted email of course). If there is more than one email address, then I recommend exporting each email address UID separately into an asc file and then sending to the corresponding email address.
Some UID may not contain an email address, but rather a photo, website or other metadata. Personally I leave those sigs intact for all email addresses or don't sign them at all if they cannot be verified.
What is a keyserver?
A key server is a repository of keys. Anyone can upload their own key there or another person's key and the key there could be manipulated by the owner of the server. DO NOT BLINDLY TRUST THE KEYS. You can use a keyserver as a convenient way to locate a key from a fingerprint, but always verify the key after downloading.
Due to the design of OpenPGP keys, 3rd party signatures can be embedded into anyone's key. This unfortunately means that an attacker can cause a DOS someone by stuffing bogus signatures into a key and make it too big to effectively use. Most gpg implementations have quietly switched to a specific keyserver based on Hagrid which strips all 3rd party certs from keys it serves:
Very few people understand that this will make the OpenPGP Web of Trust basically unusable as none of the connection data will be visible.
When sharing your key (uploading), I highly recommend using these keyservers because they allow upload of signature data:
(NOTE: uploading keys does not expose you to the above mentioned attack vector)
One can use a keyserver to search for a key via the web by prefixing with
https:// or on the commandline with the prefix
hkps:// like this:
gpg --keyserver hkps://keys.openpgp.org --search 0xC0C076132FFA7695
You can also upload your key to a server:
gpg --keyserver hkps://keys.openpgp.org --send-key YOUR_KEY_ID
Feel free to use this script I made to automate the upload of your key to keyservers, your website and / or Keybase.io.
Generally speaking, you should not send other people's keys to keyservers unless you really know what you are doing. Better to email to them and have them upload (if they choose).
Concerns about the Web of Trust
The OpenPGP Web Of Trust is not perfect. Publishing keys and personal information on public servers may open you up to receiving more spam and analysis of your social graph via key signatures. These are all concerns that might prevent someone from participating. In my mind, the overall benefits outweigh the dangers, so I participate, but many do not agree and are waiting for better options.
More details about the OpenPGP trust model in gpg
When attempting to determine to what degree a key is "trusted", gpg will offer various pieces of information explaining how the trust level is being calculated. Example:
gpg: checking the trustdb gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 4 signed: 115 trust: 0-, 0q, 0n, 0m, 0f, 4u gpg: depth: 1 valid: 115 signed: 67 trust: 3-, 0q, 0n, 2m, 110f, 0u gpg: depth: 2 valid: 50 signed: 39 trust: 35-, 2q, 1n, 5m, 7f, 0u gpg: depth: 3 valid: 3 signed: 6 trust: 0-, 0q, 0n, 3m, 0f, 0u gpg: next trustdb check due at 2019-07-09
PGP is dead
Many people have declared PGP dead because it is hard to use, doesn't protect metadata in encrypted emails and supports too much legacy crypto. Although there are very good arguments against it, I still think it is undeniable that it works well for verifying digital signatures, has wide support (hardware, software and people) and does a decent job at encrypting email once you have a properly setup client. The Web Of Trust has huge problems, but for those who take the effort to participate, it provides one of the few functioning examples of decentralized key verification. Could this be done better? Absolutely! But this is the best we have right now and attempts to replace it have always fallen short of the features needed.
RANT: Random things that confused me about gpg
Many options are not listed in the
--helpor man pages. See Esoteric Options for a few interesting ones.
The term Primary Key = "Master Key"
The term subkey refers to a key which is certified by the Primary Key
--armor= This option causes the key to be output as ASCII (instead of the default binary format). Why not use
--ascii? Furthermore, users will encounter plenty of nonsense if you forget this option while trying to encrypt a message. ALL of these will fail without a useful error message for example:
gpg --encrypt gpg --encrypt --recipient email@example.com gpg --encrypt firstname.lastname@example.org gpg --recipient 92318DBA
gpg --armor --export=2FFA7695will export ALL public keys, not just
2FFA7695as one might expect. Unlike many other gnu programs, gpg doesn't support the
=(equals sign) as value separator, so it just silently assumes you want everything.
gpg -kwill not list fingerprints or the recommended longer key ID format experts agree should be used. Instead, it lists the unsafe 8-character "short" format. Why is the default the less secure option? Use
gpg -k --fingerprint --keyid-format longinstead.
When you use
gpg --search-keys KEYID, the command will often not find perfectly valid keys (eg: those on pool.sks-keyservers.net or pgp.mit.edu). There is a bunch of keyservers, so the key you are looking for may be on any of them, or none of them, or maybe it is there, but the search algo doesn't find it.
If you add a picture (must be a jpg!), add a default keyserver, etc. it will be stored as part of your Public key. Your pub key will be changing often and should be republished.
Which actions change your pubkey?
In gpg, your "public key" is actually a collection of many pieces of metadata, user IDs, the master key and subkeys, signatures, notations and preferences. After making changes, it was unclear to me which actions changed my public key file and would require it be uploaded to a keyserver. Here is a list:
YESAdding a jpg photo.
YESAdding / revoking an identity. (NOTE: identities cannot be modified)
YESChanging the order of UIDs (identities).
YESUpdating the expiration date on keys / resigning subkeys.
YESCertifying / adding or revoking a subkey.
YESImporting a key signature from someone else.
YESAdding a keyserver url.
YESAdding notation data.
NOSigning another person's key.
NOPublishing your Public key to a keyserver.
Can I make changes to a key on a keyserver?
You can add information such as valid signatures or new UIDs, but not delete anything. You can also update expiration dates (ie adding a signature with a later expiration date).
Many ways to represent a public key...
Examples representations of my key:
- The full pubkey file is needed to verify signatures and can be represented as ASCII text or binary (default). (the file can be hundreds of kilobytes of data depending on the number of signatures).
- You can have a "hash" of the key data (used to sync key updates between servers) -
- Key "fingerprint" (160 bit sha1 hash, eg
gpg --fingerprint KEYID), normally displayed with spaces. Example:
9386 A2FB 2DA9 D0D3 1FAF 0818 C0C0 7613 2FFA 7695
- "Long" (64 bit) key ID:
C0C076132FFA7695(last 16 hex chars of the fingerprint, ie
--keyid-format long) 
- "Short" (32 bit) key ID:
2FFA7695(last 8 hex chars of the fingerprint. INSECURE: Do not rely on these) 
 Long and Short Key IDs can be prefixed with
0x to indicate they are hex.
 Short Key IDs are deprecated as they are VERY EASY to brute-force.
Cryptic symbols and key properties
When listing Secret keys (
gpg --list-secret-keys or
gpg -K) you may see:
sec= Secret (aka Private) and Public key exists for the Master key.
sec#= Master key secret is not present, only a "stub" of the private key. This is normal when using subkeys without their Master key being present.
uid= User ID. Combination of name, email address and an optional comment. You can have multiple UIDs, add and remove (
revoke) them without breaking your Master key. If you add a photo, it will be a new
uidadded to the key. When people "sign your key", they are really signing one or more of these UIDs.
ssb= Subkey Certified by the master key.
ssb>= Subkey where the private portion is on the YubiKey or another device.
When listing Public keys (
gpg --list-keys or
gpg -k) you may see:
pub= Public portion of your Master keypair.
sub= Subkey (you will never actually work with a public key for a Subkey, only the Master).
When editing a key (
gpg --edit-key KEYID) you may see:
sub*= The star indicates the particular Subkey is selected for editing.
sig!3= You see this after running the
checkcommand. The number explains the type of signature (see below).
When listing signatures (
gpg --list-sigs KEYID) you may see:
sig 3= How thoroughly was the identity claim verified (
sig 3=extremely thorough). Here is a detailed explanation.
There are different types of keys, you can see this on the right as "usage":
usage: C= Certify other keys, IE: this is your Master key.
usage: S= Sign messages so people know it was sent from you. This can be a Subkey.
usage: E= Encrypt messages to other people. This can be a Subkey.
usage: A= Authenticate yourself, for example when using SSH to log into a server. This can be a Subkey.
Multiple private keys
The local user option allows you specify the key used for signing / encryption if you have multiple private keys.
gpg --sign-key 0xBAADABBA --local-user 0xDEADBEEF
Re-signing a key
In some circumstances you may want to re-sign a certain UID, eg using a stronger hash function like SHA512, adding a notation or a new expiration date. In most cases, you will need to add the
--expert option in order to force gpg to sign the UID again.
gpg --ask-cert-level --expert --sign-key 0xBAADABBA
Exporting a specific UID
Public keys can contain a variety of UID assertions such as email address, name, photos, websites and arbitrary text. Sometimes you might want to only export a particular UID (eg when signing UIDs for a keysigning party and want to email each signed UID to the corresponding email address). You can use a complex set of filter expressions to achieve this. Here is an example:
gpg -q --armor --export \ --export-filter keep-uid="uid = Jonathan Cross <email@example.com>" \ 0xC0C076132FFA7695 > just_his_email.asc
More complex examples can be made using substring match
keep-uid="uid =~ Alfa",
|| logical connection operators, etc.
Using gnupg offline
The recommended way to use gpg in a secure manner is to keep the master key offline and only use it on an air-gapped computer. Booting into Tails OS is a convenient way to work with this kind of sensitive material as it will "forget" anything you do on the system as soon as it is restarted. Installing Tails on a USB stick works well on my MacBook Air as there is no functioning WiFi driver and furthermore it is easy to disable networking from the welcome screen. Tails now contains a modern version of Gnupg 2.1+ which fixes many known bugs in previous versions.
For everyday use, it is recommended to separate the primary (master) key from encryption, signing, and / or authentication subkeys and keep those subkeys on a hardware device (see below) while keeping the primary key offline. This allows you to use gpg easily, while ensuring that if the hardware device is lost / compromised, you can always revoke the subkeys and issue new ones without losing certification signatures on your key.
Securing your keys using a hardware device that is independent from your computer is highly recommended. This will drastically reduce the attack surface and help ensure that you are in control of the keys. Here is a spreadsheet which compares the various properties of different hardware devices.
Creating stubs on a new computer
When you are on a new computer and want to use a hardware device (like the YubiKey or the NitroKey), you will need to create on-disk "stubs" of the keys that reside on your hardware device.
On Linux, you need to add these udev rules to
sudo gpg --card-edit
Get your key stubs:
May need to change the keyring owner to yourself if it was just created with sudo above:
sudo chown -R $USER ~/.gnupg/*
Check your work by running
gpg --list-secret-keys. If you see
ssb>for the subkeys, then all is good.
Using OpenPGP with git
Configure git to sign all commits with an OpenPGP key
git config --global user.email [EMAIL ADDRESS OF YOUR PGP IDENTITY] git config --global user.signingkey [YOUR KEY HERE] git config --global commit.gpgsign true # Only works in git >= 2
You should also add your OpenPGP public key to GitHub so that verification info is displayed to users.
git and GitHub will show that code was signed with your signing subkey (rather than primary key). This may be confusing for users because normally the primary key is used / publicly shared by devs and subkeys are selected quietly in the background as needed. See example here and click on the green "Verified" button.
git log --show-signature -1 # Details of last commit sig. git log --pretty="format:%h %G? %aN %s" # Log of last commits. The "G" means good signature, "N" means no sig.
Permissions problems (YubiKey)
gpg --card-status works as root, but not as an unprivileged user.
gpg --card-status gpg: selecting openpgp failed: unknown command gpg: OpenPGP card not available: general error
Workaround: use sudo:
sudo gpg --card-status
Same with signing, but you need to explicitly add -S
sudo git commit -a -S
Linux git commit signing
I have been able to fix
git signing in Linux Mint 17.3 using
sudo sh -c 'wget -q -O - https://raw.githubusercontent.com/Yubico/yubikey-neo-manager/master/resources/linux-fix-ccid-udev | python'
I can then use
git commit -a -S to sign my commit. NOTE: If using git version >= 2, you can make this the default via:
git config --global commit.gpgsign true
gpg2 still reports an error unless
sudo is used:
gpg2 --card-status gpg: selecting openpgp failed: Unsupported certificate gpg: OpenPGP card not available: Unsupported certificate
Additional tools / scripts / documentation
- paperkey Backup / restore your gpg keys on paper.
- signing-party A fantastic collection of tools for use in key signing parties, WOT analysis, etc for *nix
I have written a few scripts to help with various PGP / GPG related tasks:
- Secure PGP keys and Yubikey NEO - Notes on GPG and YubiKey NEO setup.
- gpg.conf - Example "hardened" configuration file for GnuPG with secure defaults.
- gpg-keys-signed-by.pl - Search for PGP keys in your local keychain signed by a given key.
- send-pgp-keys.sh - Upload your GPG public key to multiple services after a change. Supports keybase, public keyservers and / or your own web server.
- search-pgp-wot - Check all signatures on a given PGP key looking for any in the Web Of Trust "Strong Set".
- email-key-uids.sh - MacOS: Split a signed OpenPGP key into component UIDs and email each to the owner via Apple's Mail.app.
- OpenBSD release key PGP signature - How to verify the OpenBSD 6.4 release signing key using OpenPGP web of trust.
- Use Apple's built-in
GPGMail(part of the fantastic GPG Suite).
- Can be setup to use a Gmail account via IMAP.
Thunderbird (Linux / Windows / Mac)
- EnigMail PGP plugin for Thunderbird v60.9.0 ONLY. In v78+ (now in testing) Thunderbird will have built-in OpenPGP support, so EnigMail will no longer be needed.
- Sync Google contacts with gcontactsync
This document comes with no guarantees, do your own homework. Feedback is welcome.
WTFPL - See LICENSE for more info.