Install and Configure GnuPG

This page will cover installing and configuring the GnuPG software.

Install GnuPG

macOS

Only one GnuPG

A lot of the problems I've seen people have with using GnuPG on macOS are caused by having multiple GnuPG programs installed on the machine at the same time.

I normally use Homebrew (see below) on every machine, and some of the packages I normally install have gnupg as a dependency. Homebrew usually ends up installing it anyway, so I have found it easier to just install GnuPG via Homebrew.

The most common "other" GnuPG installation is GPGTools (also knows as "MacGPG", "MacPGP", etc.) This distribution includes some GUI tools for managing keyrings, a System Preferences widget to configure the gpg command, and a non-free plug-in which handles PGP operations within Mail.app (to make it easier to send and received signed and encrypted emails).

The problems people have with multiple instances of gpg are usually caused by the directories in PATH being in different orders for different processes. Even if you've taken the time to lovingly hand-craft your free-range organic .bashrc (or .zshrc) file so it always puts the directories in a certain order, the fact is that not every process on the machine is going to use the shell-rc files from your home directory.

The only way I've found to ensure that every process on the machine uses the same gpg program, is to make sure the machine only has one gpg program to begin with.

The directions in this book were written using GnuPG installed by Homebrew. They will probably work with the GPGTools version of gpg, however I haven't tried it myself - I haven't used GPGTools in several years (i.e. since I discovered Homebrew).

If you already have GPGTools installed and want to use the Homebrew version instead, start by using the directions on this page to uninstall GPGTools.

Uninstall GPGTools

Uninstalling GPGTools will not affect the contents of your keyring files, although you may have to go through the config files in your $HOME/.gnupg/ directory and change a few paths after installing the Homebrew packages (this is covered below).

Homebrew

Homebrew describes itself as "The Missing Package Manager for macOS", and IMHO this is a pretty accurate statement. It provides a way to easily install most of the open-source packages commonly available for Linux, using a command line interface similar to the yum, apt, or pacman commands you would have on a Linux system.

I usually end up needing Homebrew on every macOS machine anyway, so I've gotten into the habit of just installing it on all of my machines.

Homebrew's web site has directions for how to install it. (It's easy, just copy and paste one command from the web page into your shell.)

Homebrew

Check your PATH

Once Homebrew is installed, open a new Terminal window and make sure the directory where Homebrew installs things, is listed in your PATH. This will normally be /usr/local/bin for Intel machines, or /opt/homebrew/bin for ARM (Apple Silicon) machines.

$ which brew
/opt/homebrew/bin/brew
$ echo "$PATH" | tr : '\n' | grep $( brew --prefix )
/opt/homebrew/bin

If you find that you need to update your .bashrc or .zshrc file to make sure the Homebrew path is in the right order, now is the time to do that.

Install gnupg and pinentry-mac

Once Homebrew is installed, this command will install GnuPG and the "PIN entry" program you'll need in order to securely enter passphrases under macOS.

brew install gnupg pinentry-mac

Once it's installed, you can run "gpg --version" to see what version you're running.

(jms1@jms1Air) 29 ~ $ gpg --version
gpg (GnuPG) 2.4.0
libgcrypt 1.10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-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: /Users/jms1/.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

Linux - Debian 11

This command will install GnuPG. Once of its dependencies will be pinentry-curses, which provides a "PIN entry" program that uses a terminal window to prompt you for passphrases.

apt install gnupg2

Once it's installed, you can run "gpg --version" to see what version you're running.

root@a4a47a903855:/# gpg --version
gpg (GnuPG) 2.2.27
libgcrypt 1.8.8
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-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: /root/.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

Note that the terminal-mode pinentry program requires you to set up a GPG_TTY environment variable, so that it knows where to show the prompt. You may want to add the following to your .bashrc file.

export GPG_TTY=$( tty )
gpg-connect-agent updatestartuptty /bye > /dev/null

Linux - CentOS 7

CentOS 7 normally installs GnuPG2 on every machine. You can verify whether it's already installed or not ...

[root@0e0ef5dcbfcf /]# rpm -q gnupg2 pinentry
gnupg2-2.0.22-5.el7_5.aarch64
pinentry-0.8.1-17.el7.aarch64

If it isn't installed, you can run this to install it.

yum install gnupg2 pinentry

Once it's installed, you can run "gpg --version" to see what version you're running.

[root@0e0ef5dcbfcf /]# gpg --version
gpg (GnuPG) 2.0.22
libgcrypt 1.5.3
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://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: ~/.gnupg
Supported algorithms:
Pubkey: RSA, ?, ?, ELG, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

ℹ️ The GnuPG version in the CentOS 7 repos is rather old.

Some of the configuration options mentioned below may not work.

As with Debian, the terminal-mode pinentry program requires you to set up a GPG_TTY environment variable, so that it knows where to show the prompt. You may want to add the following to your .bashrc file.

export GPG_TTY=$( tty )
gpg-connect-agent updatestartuptty /bye > /dev/null

Configure GnuPG

The GnuPG software is configured using files in each user's $HOME/.gnupg/ directory. There are two ways to update these files: using the gpgconf command, and manually editing the files.

In many versions of GnuPG, the gpgconf command doesn't recognize many of the options that can exist in the config files, so I normally edit the files by hand.

$HOME/.gnupg/gpg.conf

This file configures the gpg command itself.

Configure a default signing key

If you already have one or more PGP keys, once they're imported into your keyring you can choose one to be the default key, which will automatically be used when creating signatures.

This option normally uses a Key ID, however it can also take a name, as long as the name is unique within your keyring.

default-key     E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB

Some gpg commands print a copyright message when they start. This option disables that notice.

no-greeting

Key ID display

  • This option will make gpg commands which show keys, show the full key fingerprints of the primary and sub-keys.

    with-subkey-fingerprint
    
  • This option will make gpg commands not include a shortened version of the fingerprint when printing the algorithm (i.e. rsa4096 instead of rsa4096/B4422EBB).

    keyid-format    none
    

Together, they make the output look like this:

$ curl -s https://jms1.pub/jms1.pub.asc | gpg --show-key
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid                      John Simpson <jms1@jms1.net>
uid                      John Simpson <kg4zow@mac.com>
uid                      John Simpson <kg4zow@kg4zow.us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7

$HOME/.gnupg/gpg-agent.conf

Configure the "PIN entry" program

When gpg-agent needs to read a secret key from the keyring, it will need to ask the user to enter their passphrase. It does this by running a "PIN entry" program. There are different "PIN entry" programs out there - some work by opening a GUI dialog, some work by clearing the terminal window and "drawing" what looks like a dialog, and others may use other methods.

You need to configure gpg-agent and tell it what program to use to ask the user for the key's passphrase.

macOS - Homebrew

To use the pinentry-mac program installed by Homebrew, first find the full path to the pinentry-mac program ...

$ which -a pinentry-mac
/opt/homebrew/bin/pinentry-mac

Then edit (or create) the gpg-agent.conf file and add this line:

pinentry-program /opt/homebrew/bin/pinentry-mac

Configure secret key retention time

GnuPG uses a program called gpg-agent to hold secret keys in memory for a certain length of time. This means if you're going to be executing multiple gpg commands which require the same key, you won't have to enter the key's passphrase over and over again.

You can configure how long gpg-agent will remember the keys before deleting them from memory. (The values are in seconds.)

  • default-cache-ttl = how long keys will be held in memory before being removed. Every time a key is used, the key's "timer" is reset. Default is 600 (ten minutes). I normally use 10-30 seconds.

  • max-cache-ttl = maximum length of time that any key will be held in memory, even if it has been used recently. Default is 7200 (two hours).

default-cache-ttl       30
max-cache-ttl           30

ℹ️ These settings only affect secret keys read from the disk.

Secret keys stored in a YubiKey are never sent to the computer, so gpg-agent cannot hold them in memory.

Configure the SSH agent

The gpg-agent program can "speak the same language" as ssh-agent.

Add this option to enable support for SSH.

enable-ssh-support

When gpg-agent is working with SSH secret keys, it can also hold them in memory for a certain length of time, like it does with PGP keys. You can configure how long it holds these keys using these options. (These values are also in seconds.)

  • default-cache-ttl-ssh = how long SSH keys will be held in memory before being removed. Each time a key is used, the key's "timer" is reset. Default is 1800 (half an hour).

  • max-cache-ttl-ssh = maximum length of time that any key will be held in memory, even if it has been used recently. Default is 7200 (two hours).

default-cache-ttl-ssh   0
max-cache-ttl-ssh       0

ℹ️ These settings only affect SSH secret keys read from the disk.

Secret keys stored in a YubiKey are never sent to the computer, so gpg-agent cannot hold them in memory.

Restart gpg-agent

If you made any changes to the gpg-agent.conf file, you need to restart the gpg-agent process.

$ gpg-connect-agent killagent /bye
OK closing connection
$ gpg-connect-agent /bye
gpg-connect-agent: no running gpg-agent - starting '/opt/homebrew/Cellar/gnupg/2.4.0/bin/gpg-agent'
gpg-connect-agent: waiting for the agent to come up ... (5s)
gpg-connect-agent: connection to the agent established