
I recently discovered GPG and how awesome it is. Shortly after that, I discovered CLI-GPGâs documentation, and how not-awesome it is.
The man page is comprehensive but unwieldy â more like a glossary than a tutorial.
Thereâs The GNU Privacy Handbook. Itâs more instructive than the man page, but itâs outdated. It demonstrates gpg 0.9.4 (1999). As of today, gpg 2.2.3 (2017) is the current version. Between the 2 versions, there is good interoperability. But there are enough differences to frustrate/deter beginners.
It took me the greater part of a day to begin basic tasks with GPG. Here, Iâll list common tasks and how to perform them with modern gpg 2.2.3.
This post was originally intended for future Anton, but maybe others will make use of it too!
This article assumes you understand the basics of public key cryptography, the heart of the OpenPGP protocol.
This article also assumes youâre using MacOS and that you have the Homebrew Package Manager installed.
Unless otherwise specified, a âkeyâ (primary key, subkey, etc.) refers to a keyPAIR of public and private keys. I think this is confusing. We should always say keyPAIR if we mean a pair of 1 public key and 1 private key.
Unfortunately, referring to a keypair as a âkeyâ is standard. So in this article, I will abide.
I know youâre dying to get started sending cryptographically secure messages to all your buddies. So, letâs begin!
Installing GPG
brew install gpg
As of this day, the latest version is 2.2.3Generating Keys
gpg --full-generate-key

The --full-generate-key option will guide you through each step with helpful dialogs.
The steps:
- Choosing your key types. By default, GPG uses 1 primary key for authentication/signing, and 1 subkey for encryption/decryption. These two keys can utilize different cryptosystems. (E.g. a DSA key for signing and an ElGamal key for encryption/decryption.) However, GPG uses RSA for both keys by default. Unless you know what youâre doing, I would just stick with the RSA+RSA default.
- Choosing keysizes. Your keys can be between 1024 and 4096 bits long. The default keysize is 2048 bits long. Shorter keysizes are less secure, but more performant. Longer keysizes are more secure, but less performant. I usually opt for the max keysize: 4096 bits.
- Setting an expiration date. You can set your key to expire in N days, weeks, months, or years. Or, you can set it to never expire. The default setting is â no expiration date. If you are some high-profile person whoâs constantly at risk of having keys stolen, then perhaps youâd like to set an expiration date. Otherwise, I see no reason to do this, so long as you guard your private keys properly.
- Fill out your user ID information. Give your name, email address, and any comments youâd like to add. This information will be attached to your keys.
- Set a passphrase.
For added security,
gpgwill prompt you for a passphrase every time you perform some operation that requires access to your private keys. - Move your mouse and spam your keyboard. All of the above cryptosystems rely on random numbers to generate keys. Computers arenât capable of generating truly random numbers. They rely on a plethora of inputs with wide value-ranges to generate numbers that seem random. Mouse position and keystrokes are part of those inputs, among other things. To increase the randomness of your keys, manipulate these inputs during this section.
Youâve created your keys! In the output, youâll see rows for your primary keypairâs public key, user ID, and sub-keypairâs public key.
Listing public keys
gpg --list-public keys

This provides information about the public keys in your âcontacts listâ.
This wonât list the contents of the public keys, only metadata such as cryptosystem, keysize, and date-of-creation.
It will also show the associated user ID for a given set of public keys.
The fingerprints of primary-public keys will also be shown.
According to Wikipedia,
A public key fingerprint is a short sequence of bytes used to identify a longer public key. Fingerprints are created by applying a cryptographic hash function to a public key. Since fingerprints are shorter than the keys they refer to, they can be used to simplify certain key management tasks.
Listing ALL public keys fingerprints (Primary Keys + Subkeys)
gpg --fingerprint --fingerprint

You must give the --fingerprint command twice.
Relevant snippet from gpg manpage.Listing private keys
gpg --list-secret-keys

This provides information about the private keys you have.
For me, this output is identical to gpg --list-public-keys because I have all the private keys for each keypair I have.
Itâs possible to only have the private key/public key of a given keypair. If you have that asymmetry, then your gpg --list-secret-keys would give different output from your gpg --list-public-keys.
Why is it called secret keys?
According to dave_thompson_085 on this serverfault post,
gpg calls private keys âsecretâ because PGP dates from before people settled on the names âprivateâ key for the half of an asymmetric pair held by (ideally) only one party versus âsecretâ key for a symmetric value usually held by two or more mutually trusting parties but nobody else.
Listing key IDs
gpg --list-public-keys --keyid-format none|short|0xshort|long|0xlong

Various gpg operations target keys. E.g. deleting keys, signing files with a specific private key, etc. To specify a key, you must provide some sort of key-identification.
Key IDs fulfill this purpose.
Key IDs are essentially abbreviations of fingerprints. Hereâs a guide to key ID formats, given by Jens Erat on this superuser post.
Fingerprint: 0D69 E11F 12BD BA07 7B37 26AB 4E1F 799A A4FF 2279
Long key ID: 4E1F 799A A4FF 2279
Short key ID: A4FF 2279A short key ID is the last 8 characters of the fingerprint.
A long key ID is the last 16 characters of the fingerprint.
0xshort and 0xlong simply prefix 0x to the short and long key IDs respectively.
E.g. a short key ID would be A4FF2279. The corresponding 0xshort key ID
would be 0xA4FF2279.
The 0x is sometimes used to explicitly note that the key ID is a hex value.
Encrypting a message (binary encoding)
gpg --encrypt --recipient 'some user ID value' <file>

The default encryption format is in binary. If youâre exchanging messages via entire files, this is fine.
However, if you wish to copy/paste your encrypted message on a website (go check out /r/GPGpractice!), binary wonât work.
You canât copy/paste/type binary like normal text. If you want to interact with the encrypted message like normal text, youâll need to encode the message in ASCII armor using the --armor option. (See below)
By default, the encrypted fileâs name is <filename>.gpg. But you can specify a different filename using the --output option. (See below.)
Encrypting a message (ASCII Armor)
gpg --encrypt --armor --recipient 'some user ID value' <file>

The --armor option encodes the encrypted message in ASCII armor. This allows you to interact with your encrypted message like normal text.
With the binary encryption, you couldnât copy/paste/type it onto a forum or in an email. You canât do that with binary.
But with ASCII text, you can.
Specifying an encrypted fileâs filename
gpg --output <file> --encrypt --recipient 'some userID value' <file>

The --output option can also be used with other operations, such as decrypting a file and signing a file.
Decrypting a message
gpg --decrypt <encrypted-file>

By default, gpg will print the decrypted message to STDOUT.
You can write the decrypted message to a file using the --output option, like how it was used with encryption above.
Writing the decrypted message to a file
gpg --output <file> --decrypt <encrypted-file>

Signing a file (binary encoding)
gpg --sign <file>

Signing a file produces a new, signed file thatâs binary encoded.
IMPORTANT NOTE: Signing and encrypting a single document is a common task.
People encrypt their documents to ensure that only a specific recipient can read them (encryption).
People sign their documents to assure others that the document was sent by the themselves â that the document-senderâs identify wasnât spoofed (authentication)âŚ
âŚAND to assure others that the document was not modified from the original (integrity check).
Itâs common to perform both operations on a given document.
When you gpg --sign a document, the output is in binary.
So you might think that youâve encrypted the document, in addition to signing it.
You technically have, but you practically havenât.
I say technically, because the document was indeed encrypted with your private key. To read the signed document, it must be decrypted with your public key.
But from an encryption standpoint, how useless is that? Your public key is widely available. Basically anyone can decrypt it. Thatâs not secure at all.
Bad things might happen if you post sensitive documents, thinking that theyâre properly encryptedâŚ
TL;DR: Documents signed with gpg --sign are binary-encoded. The binary encoding might persuade you that a document is also encrypted. Itâs not. But you might think it is. So, you might publicly post documents, thinking theyâre encrypted. You might post sensitive information â that everyone can decrypt with your public key. Thatâs not secure at all.
Signing a file (readable message)
gpg --clearsign <file>

With normal gpg --sign, the outputted document is binary-encoded.
Often, you donât want this. You want the message to immediately readable, without having to decrypt it with the corresponding public key.
In other words, you just want the message to be verifiable. You donât care that everyone can see the message.
gpg --clearsign allows this. Like with gpg --sign, this embeds your signature into the outputted document.
But as the name implies, the contents of the document are clear. I.e. theyâre still readable without any decryption.
Signing a file (detached signature â in binary)
gpg --detach-sign <file>

Sometimes, you want a signature to be separate from its corresponding file.
Youâd likely do this with any file that isnât a plaintext message. E.g. programs, videos, images, audio, etc.
Why? Because signing a file alters its contents. Altering the contents of a program-file, video, etc. could break it.
Example: Signing a simple node.js program, rendering the signed file unexecutable.

Signing a file (detached signature â ASCII armor)
gpg --armor --detach-sign <file>

With a typical gpg --detach-sign <file>, the detached signature binary-encoded.
As mentioned above, binary is cumbersome for copy/pasting onto web forums, email, etc.
If youâd like to copy/paste/type your detached signature as such, encode it with ASCII armor using the --armor option.
Signing a file (specifying output fileâs filename)
gpg --output <file> --sign <file>

You can use the --output option to specify the outputted fileâs filename.
You can also do this with ASCII-armored/clearsign signatures and detached signatures.
Verifying a signed file (binary encoded)
gpg --verify <signed-file>

A signed-file thatâs binary-encoded is unreadable (unless you can read binary!).
When using gpg --verify on a binary-encoded signed-file, it will only inform you of the fileâs authenticity. It wonât decode the file for you.
If you want to decode the file/make it readable, you need to gpg --decrypt it.

Note: Running gpg --decrypt on a binary-encoded signed-file will also inform you of the fileâs authenticity â as shown above.
I.e. Running gpg --decrypt on a binary-encoded signed-file does gpg --decrypt and gpg --verify.
Verifying a signed file (clearsigned)
gpg --verify <clearsigned-file>

Verifying a signed-file with ASCII-armor is identical to verifying the binary-encoded counterpart.
Though, whatâs nice is that you donât have to gpg --decrypt the ASCII-armor signed-file to read it, since it was readable to begin with. (That is the nature of clearsigned files.)
Verifying a file with a detached signature
gpg --verify <detached-signature-file> <corresponding-content-file>

The process is identical for both binary-encoded detached signatures and ASCII-armored detached signatures.
For fun, you can try tampering with the corresponding content-file for a detached signature. Youâll see it fail.

Exporting a PUBLIC key (binary encoded)
gpg --export <key ID>

This prints the key to STDOUT in binary.
This isnât really useful, but this is the base-functionality of the command.
Exporting a PUBLIC key (ASCII armor)
gpg --armor --export <key ID>

This prints the key to STDOUT in ASCII-armor.
Exporting a PUBLIC key (write to a file)
gpg --output <file> --export <key ID>

This exports the given public key (in binary encoding) to the given file.
If you wish to export the key in ASCII-armor, simply use the --armor option.
Exporting PRIVATE keys
gpg --export-secret-keys
< Iâm not gonna show a video of this lol. >
I donât believe you can export a single private key by passing a <key ID>. Based on the man gpg, I think you can only export ALL private keys.
Importing a Public Key
gpg --import <public-key-file>

If you run gpg --list-public-keys, youâll see the newly added key in the listing.
Importing a Private Key
gpg --import <private-key-file>
The procedure for importing private keys is identical to the procedure for importing public keys.
If you run gpg --list-secret-keys, youâll see the newly added private key to the listing.
Deleting a Key
gpg --delete-key <key ID>

Searching for a Public Key on a Keyserver
gpg --keyserver <URL without scheme> --search-keys <string of info>

DO NOT INCLUDE THE URL SCHEME WHEN SPECIFYING A KEYSERVER.
E.g. DONâT INCLUDE http:// OR https:// . THIS HAS CAUSED ME A LOT OF HEADACHE.
There are various PGP Public Key Registries online. These registries are meant to facilitate the exchange of peopleâs public keys.
Here are a few major ones:
The good thing about these registries â they are all part of the SKS Pool.
The SKS Pool is a large, decentralized network of servers hosting PGP key registries.
Changes among individuals servers propagate across the entire pool, keeping the whole pool synchronized.
So, if you submit your key/update your key on one serverâs registry, your key will eventually be updated across all serversâ registries. Very cool!
For example, I originally submitted my key to pgp.mit.edu, but it has already propagated to keyserver.ubuntu.com. Check it out!

Importing a Public Key from a Keyserver
gpg --keyserver --receive-keys <key ID>

Sending a Public Key to a Keyserver
gpg --keyserver <URI> --send-keys <key ID>
< I didnât record a video because I didnât want to send this dummy PGP key to all the servers in the SKS pool. >
For many keyservers, there are also websites with GUIs for searching for keys/submitting keys.
Example: https://pgp.mit.edu's website
Minimal UI for searching for keys/submitting keys.Refreshing Keys
gpg --keyserver <URI> --refresh-keys

Sometimes, youâd like to update all the public keys you have on your public keyring.
Over time, some public keys on your ring may get new signatures, modified user IDs, etc.
Thatâs why itâs useful to refresh the public keys on your public keyring every once-in-a-while.
Setting a Default Keyserver
Add the following line to your ~/.gnupg/gpg.conf
keyserver <URL without scheme>
E.g.

Now, you donât need to specify a --keyserver for the operations above.

Signing Othersâ Public Keys
gpg --sign-key <key ID>
I did not actually upload that signature to the SKS pool. That would be unethical of me.Signing othersâ public keys is an important part of the PGP system. The PGP system is very community-oriented. It relies on a so-called âWeb of Trustâ.
Consider this: There is nothing stopping someone from publishing public keys under YOUR name.
How would people know that that public key is a spoof â that an impostor made it â that itâs not really yours?
By building your true public keyâs reputation.
PGP requires community involvement. You should always sign public keys you KNOW are real.
E.g. you know the public key that Bob gave to you is legitimate, so you should sign it.
Then, you can send it back to him ( gpg --export ).
Or, you can submit the newly-signed key to a public key registry in the SKS pool ( gpg --send-keys ). Your signature on Bobâs key will propagate throughout the SKS pool.
With this, public keys circulate with signatures attached to them.
Then, we can have the following situation:
- I trust Alice.
- I import a public key under the name of âBobâ.
- I see that Alice has signed this public key.
- Thus, Alice is claiming that this âBobâ is legit.
- I trust Alice, so by extension, I trust âBobâ to really be Bob.
- I trust Bob.
As more people sign public keys AFTER VERIFYING THAT THEYâRE LEGIT, you can start to see the âWeb of Trustâ grow.
This is how we ensure authenticity of identity in the PGP community.
Listing signatures on a Public Key
gpg --check-signatures <key ID>
If you omit <key ID>, it will print all signatures on all public keys on your public keyring.
Conclusion
Whew, that was a lot to cover! The gpg tool is very featureful and quite fun to use, but the documentation can be quite frustrating.
Hopefully this article helped you out in that respect. I know it will help future me!
Opinions expressed in these articles do not represent those of my employer.