How GPG works

While GPG is great software, it is said to be hard to use. For me, the hardest part is to sit down and get acquainted with the software. Actually, this is not a problem with GPG per se, but with all software. Let me give you an example: When you do not know vim, you will have a hard time editing text with vim. First, you have to get familiar with software before being able to use it. Usually, you would want to read (or at least skim) some kind of manual. And this is the problem with GPG: For me, the manual is similar to a beginner’s tutorial, since it misses quite a few things that should be discussed if you really want to use this software properly.

While writing the backup software bkup, I wanted to make use of GPG for encrypted backups for one particular reason: Asymmetric keys. This means that a key consists of two parts, a public and a private key. The private key is protected by a password and should be used by one person only. The public key is — as the name suggests — public, thus not protected by a password, and can be used by anybody. This is a nice property: For encrypting backups you only need to use the public key, so no password is necessary which means that the nightly backup can run unattended in a secure way; only for accessing the backups a password is needed as the private key will be used.

This page is basically a log of all the things I have learned while implementing bkup. It is not intended to be a GPG manual or tutorial, as there are already many out there. I am not even sure whether this page is of use to anybody except for me. So, if there are some things I glossed over, or did not explain too well, follow the links I have provided, and learn for yourself. It is a worthwhile endeavor!

Since we have already seen the merits of the GPG system, we want to get started. So, let’s create some keys. But wait… what keys? There are several to choose from.

Key creation: RSA, DSA, or ELG?

GPG supports three encryption schemes:

While maintaining two separate keys — one key for signing and one for encryption — sounds like a lot of redundant work there is indeed merit in this approach: Mathematically, there is no difference between signing a message and decrypting a message. In both cases your private key will be used as an input to the same algorithm. Now, imagine a malicous user tricking another user into decrypting a message by asking him to sign it. One approach to mitigate this attack is that messages are never signed directly; instead, the signature is made on a secure hash of a message. Another approach is to use two different keys, one key for each of these operations. That way, such an attack would also be thwarted.

You can see the allowed uses of a GPG key by using the command line option --edit-key:

$ gpg2 --edit-key <key-id>

pub  4096R/DEADBEEF  created: 2011-09-24  expires: never       usage: SC
                     trust: ultimate      validity: ultimate
sub  4096R/CAFEBABE  created: 2011-09-24  expired: 2014-08-06  usage: E
sub  2048g/BA5EBA11  created: 2014-08-04  expires: 2015-09-15  usage: E
sub  4096R/CA55E77E  created: 2014-08-06  expires: never       usage: S

The meaning of the usage flags is as follows:

Usage Meaning
S sign/verify message
C certify (sign another key)
E encrypt/decrypt message
A authentication (log in to SSH host using a GPG key)

One key to rule them all (Subkeys and identities)

One topic that comes up quite often is the topic of subkeys. Frequently, this topic appears to be complicated but indeed it is not. One thing to remember is not to confuse subkeys with user identities. These two concepts are not the same! You can bind several subkeys to one GPG key, and you can also bind several user identities to the same GPG key. However, selecting an identity does not select a specific subkey for you. They belong all to you, and you can combine them at your will.

To make the concepts of subkeys and user identities a little bit more clear, let me give you an example: Suppose a single GPG key has subkeys 1, 2, and 3, and is associated with the user identities A, B, and C. In one scenario you can use identity A with subkey 1, in the next scenario you can use identity A with subkey 2.

Let us practice with GnuPG:

The need for multiple identities

Imagine that you have an established GPG key where several people have signed your key, and you have signed theirs. It was a lot of work to build the web of trust, and now you need to switch email addresses for whatever reason (different job, etc). Of course, you want to continue to use your established key with your new email address (and possibly let everybody know that you have retired the old address). This is where GPG’s identities come into play:

  1. You add your new email address to the key.
  2. Eventually, you revoke your old email address.
  3. You publish the changes to your key.

Nothing else changes, in particular you can continue to use your (sub)keys just like you always did. Even better, none of your peers need to do anything (except update your key).

But now, imagine that you own such a key for several years and by accident this key was compromised (for example, somebody got access to your laptop). Isn’t this bad? Sure it is, as it means that you have to throw away your key and rebuild the web of trust from scratch. Years of work lost. Except… if you had been using subkeys.

The need for subkeys

The idea of using subkeys is simple but its implementation can be hard depending on the particular version of the program you are using and the work flow you want to build. Let’s start with the idea and let us revisit the above example: You own a key or, to be more precise, a public-private key pair. You want to prevent that your private key gets stolen when somebody gets access to your laptop. That’s easy: Do not store the private key on the laptop. You do not need to care about the public key, as it is public anyway. All is fine and good, except that you cannot sensibly use your key any more: For signing and decrypting messages you need to access to the private part of your key.

To increase security and to have the private part of your GPG key on your laptop, you need two keys:

  1. The GPG master key, and
  2. a GPG subkey.

Both keys consist of at least a public and private key pair, possibly more if you decided to use different keys for signing and encryption. Now, you do the following: You split the GPG master key into the public and the private keys, and keep only the public GPG master key on your laptop. The private key you put somewhere safe (eg a USB pen drive hidden in a drawer in your home). Additionally, you put the complete GPG subkey (public and private part) on your laptop, and use only this key for “real” work (work unrelated to GPG itself).

In case your laptop gets compromised using this setup, the following will happen:

Hence, you need to use the GPG master key to revoke your compromised subkey, generate a new subkey, and publish your changes. Be aware that these key operations can only be signed with your primary key, so it is really important that the primary key is never compromised!

That is the high-level view. Of course, the actual implementation includes many details. Let’s get our hands dirty!

Hands on: Secure your master key

The following steps will give you a (public and private) master key pair in a secure location, and a public master key with public and private subkeys on your work computer:

  1. On a dedicated (extra secure) machine, create a primary key, as well as at least one subkey. Then, make a backup copy of ~/.gnupg in case anything goes wrong:

    cd && tar -cf gnupg.tar .gnupg
    
  2. Export your secret key so that you can put it in a safe place:

    gpg2 --export-secret-keys <master-key-id> > all-priv.gpg
    

    Either directly write the file to the target media (for example a USB stick), or use a tmpfs directory such as /run/user/$UID as a temporary storage. If applicable, protect this file with chmod 400. Consider printing it with paperkey. Now it is also a good time to generate a revocation certificate for the master key, and store it in a safe place far away from the master key itself.

  3. Change the pass phrase for unlocking your sub keys so that attackers can not use the master key if they learn your day-to-day credentials:

    gpg2 --edit-key <master-key-id>
    passwd
    
  4. Use export-secret-subkeys to export all of the keys (private and public, primary and subkeys) but the private master key to an external file:

    gpg2 --export-secret-subkeys <master-key-id> > sub-priv.gpg
    
  5. In case you already have private parts of the key on the target machine (or you want to treat your main machine like all other machines), you need to delete your private keys first: GnuPG before version 2.1 is not able to merge private keys and hence will skip this key during import altogether. To delete all secret keys (master and sub keys):

    gpg2 --delete-secret-key <master-key-id>
    
  6. Then, use the previously generated file to import your private keys except for the private master key:

    gpg2 --import < sub-priv.gpg
    
  7. To check that your key now really consists of only the public part, try to print the private key:

    gpg2 -K <master-key-id>
    

    The output should show sec# instead of sec for your private key. This indicates that there is a private key, but it is missing right now.

  8. When you are in need of the private master key to perform some key operation, simply mount the USB drive (or restore your key to a tmpfs such as /run/user/$UID) and --import your credentials. Eventually, the following command line switch could be handy as well:

    gpg2 --homedir /run/user/$UID
    

    Do not forget to shred the sensitive temporary files after finishing your updates! Done.

By the way, if you have ever wondered what sec, sub, ssb and the other abbreviations mean, have a look at the following table:

Abbrev. Meaning
pub public key
sub public subkey
uid user identifier
sec secret key
ssb secret subkey

GPG on multiple machines

When dealing with multiple machines, one question that inevitably pops up is whether one should create multiple keys for different machines. At least we have learned that private SSH keys must never be moved away from the machine they were created for. In this respect, GPG works differently: Private keys are not tied to a particular machine but to a particular identity. It is perfectly fine to share private keys between machines as long as they are exchanged in a safe manner. The private key is additionally protected by a password, and there is little incentive to steal a password-protected key when you already have access to the machine where sensitive documents are processed or stored.

How to synchronize the machines? The answer to this question really depends on the use case for a given machine. Fact is, you only need to protect private keys and owner-trust information. Public keys do not need to be protected and thus can be exchanged safely via key servers or other public means:

gpg2 --send-keys <master-key-id>
gpg2 --refresh-keys

For synchronizing in a safe manner or without relying on third-party services SSH comes in handy:

gpg --export             | ssh user@remote.host 'gpg --import'
gpg --export-secret-keys | ssh user@remote.host 'gpg --import'
gpg --export-ownertrust  | ssh user@remote.host 'gpg --import-ownertrust'

Or when pulling:

ssh user@remote.host 'gpg --export'             | gpg --import
ssh user@remote.host 'gpg --export-secret-keys' | gpg --import
ssh user@remote.host 'gpg --export-ownertrust'  | gpg --import-ownertrust

Merging private subkeys

One issue that may come up if you are working on multiple machines is that you generate new sub key pairs (public and private keys) on different machines and forget to merge them before it is too late. Suppose you have two machines; on the first machine you create the first sub key pair A, and on the second machine you create the second sub key pair B. This is not a contrived example, it happened to me after buying a new laptop. The old laptop had a sub key the new one did not have, and vice versa. Needless to say, you want both sub key pairs to stay around, attached to one master key. How do you do that?

There are several solutions to this problem.

Gpgsplit is so versatile that you can even convert master keys to sub keys.

Choosing a key server

Key servers are a nice way to make your public keys public. Everybody can install their own key server if they wish to. Usually, these key servers are interconnected, which means that when submitting a key to one key server, it will end up on several key servers. (Removing a key from key servers is not possible.) Due to the distributed nature of the key server infrastructure, it may happen that some key servers lag behind. Fortunately, when querying key servers one can choose a well-maintained server as the status of SKS key servers is publicly available.

Extend key expiry

Choosing encryption/compression algorithms

Now that you are well versed in the use of GPG, we can turn towards more elaborate uses. When using a backup system, for example, you can perfectly filter your data through GPG, and you will get scrambled output. But how do you know whether the resulting output is really encrypted, and with which options? Which ciphers have been used? Was the correct key used? Was the plaintext compressed before it was encrypted?

These are valid questions, and one handy tool seems to be pgpdump (git repo). However, you have first to install the tool to be able to use it, and there is already another easy way at your fingertips:

some gpg output... | gpg2 --list-packets

An example output is:

:pubkey enc packet: version 3, algo 16, keyid ...
	data: [2048 bits]
	data: [2042 bits]
:encrypted data packet:
	length: unknown
	mdc_method: 2
gpg: encrypted with ELG key, ID ...

How to interpret this data? One can clearly see that the data is encrypted, and it gives the encryption key used. Without any further specification, GnuPG will always use the most recently self-signed subkey to encrypt messages, even if a particular subkey has been provided on the command line. To override this default behaviour and select a different key you have to use the exclamation-mark syntax on the subkey in question:

input data... | gpg2 -e -r 'deadbeef!'

A GPG stream consists of several packets, each describing a particular payload. Here, encryption has obviously happend with algorithm 16 (which refers to the Elgamal method, see RFC 4880), and the modification detection code packet (MDC) (a kind of checksum) uses algorithm 2 (here: SHA1, see the table below). Custom data will be encapsulated in a user attribute (UAT) packet, which is absent in the example above.

# Cipher S Hash H Compression Z
0     Uncompressed
1 IDEA MD5 ZIP
2 3DES SHA1 ZLIB
3 CAST5 RIPEMD160 BZIP2
4 BLOWFISH    
5      
6      
7 AES    
8 AES192 SHA256  
9 AES256 SHA384  
10 TWOFISH SHA512  
11 CAMELLIA128 SHA224  
12 CAMELLIA192    
13 CAMELLIA256    

There are two ways to set a particular algorithm:

  1. The recipient may specify algorithm preferences by editing a particular identity of his.
  2. The sender may override the recipient’s algorithm selection by using command-line switches.

To set the algorithm preferences as the message recipient, edit the key in question and use the pref, showpref, setpref, and updpref commands, respectively:

gpg2 --edit-key ...

gpg> pref
[ultimate] (1). Alice <alice@example.org>
     S9 S8 S7 S3 S2 H8 H2 H9 H10 H11 Z2 Z3 Z1 [mdc] [no-ks-modify]

gpg> showpref
[ultimate] (1). Alice <alice@example.org>
     Cipher: AES256, AES192, AES, CAST5, 3DES
     Digest: SHA256, SHA1, SHA384, SHA512, SHA224
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify

gpg> setpref S9 S7 S2 H10 H2 Z2 Z0

gpg> updpref

The message sender is not bound to the preferences the recipient has suggested using the method above; instead, he can choose an algorithm using command line switches. For this, use --personal-cipher-preferences, --personal-digest-preferences, or --personal-compress-preferences (preferred), or — if you are careful enough not to violate the standard — --cipher-algo, --digest-algo, or --compress-algo. See the man page of gpg2(1) for more details.

Storing GPG keys permanently off-line

Now that we have secured our public/private key pair physically by removing its private part from all everyday machines, and we have strengthened confidentiality by choosing strong cryptographic algorithms, we want to make sure that the private part of the key remains retrievable even if the chosen secondary memory (USB drive, magnetic hard disk, SSD, etc) becomes unreadable. One way is to use paperkey to extract the secret bits from the key and print them on paper. While this is nice, this work flow can be made more pleasant by using a QR code instead of — or better: additionally to — plain text. If the QR solution is too much work, one could also consider using PaperBack.

Using GPG with SSH

Another nice use case of GPG is to use its keys as an authentication mechanism for SSH. This is a rather new feature, so be prepared that there may be still unresolved issues. The starting point for implementing this feature would be to check out the man page for gpgkey2ssh.

GPG automated signing

And now for the final trick: Sometimes it is necessary to sign documents automatically to certify their originality to the recipients. This can be achieved with GPG as well, although you have to make sure that the machine where the signing takes place is highly secured, as there will be no pass phrase on the secret key.

Conclusion

That’s all for now. As said before, GPG is not so difficult to use once one has learned a few simple concepts. Of course I did cover only a small subset of GPG’s functionality but that’s okay as long as we learned something. I intend to update this page when I learn new things about GPG, so if the permalink moves make sure to check the newer content as well.