It always seems that just enough time has passed since the last time I worked with GnuPG for me to forget not just the exact syntax of these commands completely but the workflow in general. Here are some basics about using GnuPG and managing keys. If you need to know more about GnuPG, I would suggest reading Linux Security Cookbook by Daniel J. Barrett et al.

Installing GnuPG

The GnuPG package is installed by default. You verify this and get the version like so:

rpm -qa | grep ^gnupg

Setting up the user environment

This may not be required, but is not a bad idea to add a couple of lines to your ~/.bashrc:

GPG_TTY=$(tty)
export GPG_TTY

Managing GPG Keys

'gpg: cancelled by user' error

If you run into the gpg: cancelled by user' error when generating a new key or a certificate, try doing this:

# As the user who is having the issue run the 'tty' command 
# and note the pts number
tty 
# /dev/pts/1 

# Then become root and adjust permissions on that pts:
sudo su - root
chmod o+rw /dev/pts/1

Make sure you are the user you think you are. I can’t tell you how many times I screwed this up.

su - <username> && id

List existing public and private keys

gpg --list-keys --with-fingerprint && gpg --list-secret-keys --with-fingerprint

Delete any unneeded public or private keys

gpg --delete-key <key_id>
gpg --delete-secret-key <key_id>

Change key passphrase

Suppose you need to change the passphrase on an existing key. This only affects the private key. The public key remains unchanged, so you don’t need to re-send it to people.

gpg --edit-key <key_id>

Generate a new GPG key pair

It is a good idea to set an expiration date for your key. The current standard used by many financial institutions is 23 months or less.

cd ~ && gpg --gen-key

Set the key trust level

Because this is your key, set the trust level to 5.

gpg --edit-key <key_id>
trust

Export a public key to binary format

This format works well for distributing the key via file-sharing apps like cloud storage, SFTP, etc.

gpg --output gpg_user1_email@domain.com.$(date +'%F').ascii.pub.key --export email@domain.com

Export a public key to an ASCII-armored key file

This format is suitable for sharing via text-centric apps like email, chat apps, etc.

gpg --output gpg_user1_email@domain.com.$(date +'%F').bin.pub.key --armor --export email@domain.com

Create a key revocation certificate

This certificate can be used to revoke a compromised key pair.

# Obtain the secret key ID
gpg --list-secret-keys

# Create the revocation cert
gpg --gen-revoke <key_id> > ~/.gnupg/revocation_<key_id>.crt

# Set permissions
chmod 600 ~/.gnupg/revocation_<key_id>.crt

Revoking a key

When you revoke a key, this only affects your local machine. You will no longer be able to use this key. But someone else might if they got their hands on your private key (which is probably why you’re revoking the key in the first place). It is therefore important to send your revoked key to a keyserver (see the following section) so that others are aware of your misfortune. This is a flaky process, though, as few people bother using keyservers or are regularly validating keys.

gpg --import ~/.gnupg/revocation_<keyID>.crt
gpg --send-keys <key_id>

Using public keyservers

The situation with the public keyservers has traditionally been a mess. Every few years, they seem to come and go. If you’re relying on public keyservers to distribute your keys, you would need to stay on top of this and regularly check the status of any servers you’re using.

Set the default key server

Edit your gpg.conf and update the keyserver setting to show keyserver hkps://keys.openpgp.org` or whatever other keyserver you would like to use as the default. The keyserver can also be specified from the command line using the --keyserver keyserver_address option.

vi ~/.gnupg/gpg.conf

Verify key server status

You can verify that the keyserver is responding like so:

for i in 80 443; do nc -v -i1 -w1 keys.openpgp.org ${i}; done

Publish your key to a PGP keyserver

gpg --send-keys <key_id>

Search for public keys on a keyserver

The string can be an email address, key ID, or key fingerprint. The latter is the best option to avoid the confusion of multiple keys associated with the same email address or short vs. long key IDs. Remember that the fingerprint should contain no spaces.

gpg --search-keys <string>

You can use the one-liner below to search the keyserver for all the keys in your local key chain.

for i in $(gpg --list-keys --with-fingerprint | grep fingerprint | awk -F'=' '{print $NF}' | sed 's/ //g'); do 
gpg --no-tty --search-keys ${i} 2>/dev/null
done

Import a key from a keyserver

gpg --recv-keys <key_id>

GPG and SSH keys

GPG is often used to encrypt SSH keys, so this is just a quick overview of this process.

Generate SSH key pair

ssh-keygen -f ~/.ssh/id_rsa_$(date +'%F') -t rsa -b 4096 -C "email@domain.com"

Generate a PGP-signed version of the SSH public key

Similarly to generating signed versions of the PGP public key, you can use binary or ASCII-armored formats.

# Provide the passphraze for the GPG key you're using
read -s gpg_password

# Output binary format
gpg --passphrase "${gpg_password}" --batch --sign -o ~/.ssh/id_rsa_$(date +'%F')_signed_bin.pub ~/.ssh/id_rsa_$(date +'%F').pub

# Output ASCII format
gpg --passphrase "${gpg_password}" --batch --sign --armor -o ~/.ssh/id_rsa_$(date +'%F')_signed_ascii.pub ~/.ssh/id_rsa_$(date +'%F').pub

Encrypting and decrypting files

Simple file encryption using a password

This encryption method does not use any keys – just a password. This is less secure but, obviously, very convenient.

read -s gpg_passwd
gpg --batch --symmetric --quiet --yes --passphrase "${gpg_passwd}" "${file_name}" 2>/dev/null

Simple file decryption using a password

A file encrypted with a password (as shown above) can be decrypted like so:

read -s gpg_password
gpg --batch --decrypt --passphrase "${gpg_password}" -z 2 "${file_name}" 2>/dev/null

Encrypt a file using the recipient’s public key

You can use either the recipient’s email address or the key ID as a value for the --recipient argument.

gpg --output "${file_name}.gpg" --encrypt --recipient "${recipient_email}" "${file_name}"

Decrypt a file using the recipient’s private key

gpg --output /tmp/test_crypt.txt --decrypt /tmp/test_crypt.txt.gpg

# Or do this non-interactively
read -s gpg_password
gpg --batch --passphrase "${gpg_password}" --output "${file_name}" --decrypt "${file_name}.gpg"

Using GPG with logrotate

This is an oddity, but you can use GnuPG with logrotate to encrypt your rotated log files. Usually, log files are harmless, but not always. On occasion, devs enable verbose logging for troubleshooting purposes. Doing so can leave potentially sensitive data in the log files. If this had happened before, it would happen again.

Here’s an example of a custom /etc/logrotate.d/squid that uses gpgto encrypt data during log rotation.

/var/log/squid/*.log {
    daily
    rotate 5
    compress
    compresscmd /usr/bin/gpg
    compressoptions --always-trust --encrypt --recipient your_email@domain.com
    compressext .gpg
    notifempty
    missingok
    sharedscripts
    postrotate
      # Asks squid to reopen its logs. (log_rotate 0 is set in squid.conf)
      # errors redirected to make it silent if squid is not running
      /usr/sbin/squid -k rotate 2>/dev/null
      # Wait a little to allow Squid to catch up before the logs is compressed
      sleep 1
    endscript
}