GPG Tutorial

Overview

Introduction

GnuPG is a cryptography tool that helps you manage public and private keys as well as perform encrypt, decrypt, sign, and verify operations. It is an open-source version of PGP. This tutorial will go over basic key management, encrypting (symmetrically and asymmetrically), decrypting, signing messages, and verifying signatures with GPG.

There are bindings to most programming languages so you can use it within your own custom application, but this tutorial is focused on the command-line utility gpg.

In this tutorial, the word 'message' is synonmous for 'file' or 'document'. You can encrypt and sign binary files just the same as text messages.

Install GPG

You can find the download links for all available platforms and source code on the official GnuPG website.

Windows

On Windows, I recommend the Gpg4win application. You can find the installer at Windows GnuPG installer (Gpg4win) download page. Just run the installer and then gpg will be available in your command prompt.

Mac

The easiest way to install on Mac in my opinion is using Mac Homebrew. There is a formula for gpg named gnupg: GPG for Mac Homebrew. You will need to install brew first if you don't already have it.

# Install on Mac
brew install gnupg

Linux

Most Linux distributions have gpg in their package repository. Check with your specific distribution to find what the gpg package name is. It might be gnupg or gpg2 or some variation.

# On Debian/Ubuntu based distros
sudo apt-get install gpg

Android

There is an Android version available Android GnuPG

Basic usage

To get started and make sure it is installed correctly, run gpg with the --help flag to print out the version number, supported encryption and hash algorithms, and all the usage options. This will give you an overview of all the features GPG has.

gpg --help

Example output of gpg --help:

gpg (GnuPG) 2.2.10
libgcrypt 1.8.3
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later https://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: C:/opt/gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Syntax: gpg [options] [files]
Sign, check, encrypt or decrypt
Default operation depends on the input data

Commands:

 -s, --sign                  make a signature
     --clear-sign            make a clear text signature
 -b, --detach-sign           make a detached signature
 -e, --encrypt               encrypt data
 -c, --symmetric             encryption only with symmetric cipher
 -d, --decrypt               decrypt data (default)
     --verify                verify a signature
 -k, --list-keys             list keys
     --list-signatures       list keys and signatures
     --check-signatures      list and check key signatures
     --fingerprint           list keys and fingerprints
 -K, --list-secret-keys      list secret keys
     --generate-key          generate a new key pair
     --quick-generate-key    quickly generate a new key pair
     --quick-add-uid         quickly add a new user-id
     --quick-revoke-uid      quickly revoke a user-id
     --quick-set-expire      quickly set a new expiration date
     --full-generate-key     full featured key pair generation
     --generate-revocation   generate a revocation certificate
     --delete-keys           remove keys from the public keyring
     --delete-secret-keys    remove keys from the secret keyring
     --quick-sign-key        quickly sign a key
     --quick-lsign-key       quickly sign a key locally
     --sign-key              sign a key
     --lsign-key             sign a key locally
     --edit-key              sign or edit a key
     --change-passphrase     change a passphrase
     --export                export keys
     --send-keys             export keys to a keyserver
     --receive-keys          import keys from a keyserver
     --search-keys           search for keys on a keyserver
     --refresh-keys          update all keys from a keyserver
     --import                import/merge keys
     --card-status           print the card status
     --edit-card             change data on a card
     --change-pin            change a card's PIN
     --update-trustdb        update the trust database
     --print-md              print message digests
     --server                run in server mode
     --tofu-policy VALUE     set the TOFU policy for a key

Options:

 -a, --armor                 create ascii armored output
 -r, --recipient USER-ID     encrypt for USER-ID
 -u, --local-user USER-ID    use USER-ID to sign or decrypt
 -z N                        set compress level to N (0 disables)
     --textmode              use canonical text mode
 -o, --output FILE           write output to FILE
 -v, --verbose               verbose
 -n, --dry-run               do not make any changes
 -i, --interactive           prompt before overwriting
     --openpgp               use strict OpenPGP behavior

(See the man page for a complete listing of all commands and options)

Examples:

 -se -r Bob [file]          sign and encrypt for user Bob
 --clear-sign [file]        make a clear text signature
 --detach-sign [file]       make a detached signature
 --list-keys [names]        show keys
 --fingerprint [names]      show fingerprints

Please report bugs to https://bugs.gnupg.org

Key management

When it comes to keys there are private(secret) keys and public keys. They are paired together. The public key is, as expected, something you can make public and share with others. The private key is like your secret password though, don't share that one with anyone! You might have the public key of many people stored on your computer but the only private key you will probably have is your own.

List keys stored locally

# List public keys you have stored (yours and other people's keys)
gpg --list-keys

# List private keys (generally only your own)
gpg --list-secret-keys

Create a new private key

Use the --gen-key flag to create a new secret (private) key. This will walk you through an interactive prompt to fill out the questions like what is your name.

gpg --gen-key

Export a private key

You might want to export your private key in order to back it up somewhere. Don't share your private key with other people though. You can export in armored (ASCII) format and you could actually print it out on paper or write it down since it is human readable and put it in cold storage. Text format may also work better than binary in certain communication mediums.

# Find the ID of your key first
# The ID is the hexadecimal number
gpg --list-secret-keys

# This is your private key keep it secret!
# Replace XXXXXXXX with your hexadecimal key ID
gpg --export-secret-keys --armor XXXXXXXX > ./my-priv-gpg-key.asc

# Omitting the --armor flag will give you binary output instead of ASCII
# which would result in a slightly smaller file but the ASCII
# formatted (armored) can be printed physically, is human readable,
# and transfered digitally easier.
# Both formats can be imported back in to GPG later

Delete a key

You can delete a private key from local storage with the following command:

# Private keys
# Use the ID listed with --list-secret-keys
gpg --delete-secret-keys XXXXXXXX

# Public keys
# Use the ID listed with --list-keys
gpg --delete-keys XXXXXXXX

Import a key

If you need to import a private key you can use the following command. This is useful if you are on a new computer or a fresh install and you need to import your key from a backup.

# This works the same for binary or ASCII (armored) versions of keys
# This is also the same for private and public keys
gpg --import ./my-priv-gpg-key.asc

Push your public key to key server

You may want or need to publish your public key somewhere where everyone can find it. For example, to push code to the Maven central repository, you must sign your code with a GPG key that has a public signature somewhere like the MIT public key server. You can push your public key using the --send-keys flag.

# There are many public key servers out there, not just MIT
# Replace XXXXXXXX with your key id from --list-keys
gpg --keyserver hkp://pgp.mit.edu --send-keys XXXXXXXX

Encryption

There are two types. Symmetric and asymmetric. GPG supports many different algorithms for each method. The most commonly known ones are AES for symmetric and RSA for asymmetric. ECDSA is starting to slowly replace RSA though. The following examples will demonstrate how to do both symmetric and asymmetric encryption as well as decrypt a message.

Encrypt with a passphrase (symmetric)

Can be decrypted by anyone with the passphrase. No specific recipient. Passphrase can be shared with many people. This can be useful for just encrypting files locally with a simple passphrase, or to encrypt a document before sending it to someone. You'll have to find another channel to send them the passphrase though if it is not already exchanged before-hand.

There are two formats of output you can get: binary and text. The binary version will take up less space, but the ASCII version is a little easier to work with and can be transported over text means, say, pasted in to an email. They both decrypt the same way.

gpg --symmetric message.txt
# Prompts you for a passphrase
# Creates message.txt.gpg (binary)

gpg --armor --symmetric message.txt
# Same, but ASCII format output instead of binary
# Creates message.txt.asc (ASCII)

# Specify the encryption algorithm
gpg --symmetric --cipher-algo AES256

# Get the list of cipher algorithms
gpg --version
# E.g. 3DES, BLOWFISH, AES256, TWOFISH

# Specify output file
gpg --output message.txt.gpg --symmeteric message.txt

# Encrypt and sign (all in the single output file)
gpg --sign --symmetric message.txt

You can also encrypt and sign at the same time. Signatures are covered in more detail in the Signatures section below.

Encrypt for a single recipient (asymmetric)

You can encrypt a message for a single specific recipient. You do this by encrypting asymmetrically with your private key and the recipients public key. By doing this, only the recipient's private key will decrypt the message. You will need the recipient's public key in order to do this. They can share their public key with you directly, or you can search public key servers.

# Import NanoDano's public GPG key
gpg --keyserver pgp.mit.edu --search-keys nanodano@devdungeon.com

# It will print a list of matching results.
# Enter the number next to the one you want to import
# After it's imported you can verify the public key is stored with
gpg --list-keys

After you have the receipient's public key imported, you can encrypt messages that only they can decrypt.

# This will prompt and ask the recipient's email address
# and you will have to enter the ID or email
gpg --encrypt message.txt

# or specify the recipient as the -r argument
gpg  --recipient nanodano@devdungeon.com --encrypt message.txt
# Encrypted output will be in message.txt.gpg

# Encrypt and store in ASCII format (message.txt.asc)
# Both binary and ASCII versions decrypt the same
gpg  --armor --recipient nanodano@devdungeon.com --encrypt message.txt

# Encrypt and sign at the same time
gpg --encrypt --sign --recipient nanodano@devdungeon.com message.txt

# Specify output file
gpg --output message.txt.gpg

Decrypt a message

You can decrypt messages with the -d or --decrypt option. It will automatically determine if it is symmetrically encrypted with something like AES and it needs a passphrase, or if it was encrypted asymmetrically with something like RSA and it needs to look for a private key. The recipient will be detected automatically and GPG will search locally to see if the private key is stored. If it is, it will ask for the passphrase and then print out the decrypted message to the console. If it is a symmetric encryption it will prompt you for the passphrase, and then print the message.

# Decrypt and print message to screen
# Will automatically verify signature if there was one
# Will automatically detect if symmetric or asymmetric
# Will automatically use the appropriate private key if available
# Will automatically prompt for passphrase if symmetric
gpg -d message.txt.gpg

# Decrypt and put output in decrypted.txt
gpg --decrypt message.txt.gpg > decrypted.txt

Signatures

You can sign files that were encrypted using asymmetric or symmetric methods. The benefit of providing a signature is to let everyone prove that you were the author of the file, or at least, you confirmed the contents of the file at the time of your signature. You can also just sign files without encrypting them at all.

Sign a message

You can use the sign feature without any encryption. That is, if you want to share something in plain-text or make a public post that everyone can read, but you want to include a signature to prove you were the original author.

The resulting output file is the unencrypted original document with a signature at the end. It is not used to encrypt and secure the information and guarantees no confidentiality. It only proves integity and authenticity of the message. You can create a binary signature or a plain-text signature.

gpg --clearsign message.txt
# Outputs message.txt.asc in plain text, suitable
# for pasting in an email or posting online

gpg --sign message.txt
# Outputs message.txt.gpg a binary file

# Both of these can be verified with --decrypt
# but they are not _actually_ encrypted.
gpg --decrypt message.txt.gpg
gpg --decrypt message.txt.asc
# This will print out the message along with the signature info

Encrypt and sign

You can encrypy-and-sign a message in one step. This will attach the signatures to the encrypted file. With these two encrypt-and-sign methods below, the signature is included in the encrypted .gpg/.asc file that is output. When someone decrypts them, the signature will be checked automatically.

# Symmetric encrypt with signature
gpg --sign --symmetric message.txt

# Asymmetric encrypt with signature
gpg --sign --encrypt -r nanodano@devdungeon.com message.txt

Verify signatures

If a signature is included in the encrypted file, GPG will automatically output the verification of the signature when it decrypts the message. You don't have to take any special action to verify the signature you just use the normal -d or --decrypt option, it happens by default.

# When you decrypt the message it will verify the signature
gpg --decrypt message.txt.gpg
gpg --decrypt message.txt.asc

You can also manually verify a signature for things like a clear signed file with the --verify option like this:

# Verify a signed message that included a signature
gpg --verify message.txt.asc
gpg --verify message.txt.gpg

Detached signatures

So far all the signatures we have seen have been embedded in to the file with the message. It is also possible to separate the signature file from the message file. This is called a detached signature.

# Create a separate signature file
gpg --detach-sign message.txt
# Will create message.txt.sig

# This verify will automatically check the signature
# against a file named "message.txt"
gpg --verify message.txt.sig

# Specify the file to check it against
gpg --verify some_signature.sig ./message.txt

Conclusion

After reading this, you should understand how to use GPG for its most common tasks like creating and managing keys, encrypting symettrically with AES, encrypting a message for a specific person with RSA, and how to sign and verify signatures.

This was not a comprehensive overview of all the GPG features. It was only a brief overview of some basics. Here are some notable things that are not covered here:

  • Plugins for applications like Outlook and Thunderbird to add GPG encryption support.
  • Trusted rings
  • Signing people's public keys
  • Good encrpytion habits
  • Revocation keys

Read more about all the features on the Official GnuPG documentation.

Reference links