This post is a short memo as regards the usage of GnuPG aka Gnu Privacy Guard aka GPG for short.

Date Version Author Comment
2015-10-02 1.0 SV Initial version
2017-03-14 2.0 SV Updated version covering key migration

Table of Content

GnuPG is an implementation of the OpenPGP standard also known as RFC4880.

It defined an hybrid encryption framework based on the notion of Web of Trust to offer basically Mail | Document | Git commit... encryption / signature.

Installation / Setup

Apart from the below (preferred) solutions per OS, a cross-platform approach relies on Thunderbird and the Enigmail extension.

Linux/BSD

Mac OS X

  • Install the GPGTools Suite
    • GPG for Apple Mail and GPG Keychain
    • GPG Services and MacGPG

Create a GPG key Key list Write secure messages Secure messages received In case of errors

Windows

Gpg4win (GNU Privacy Guard for Windows) is the reference package implementation to use GPG under windows – tutorial

It includes the following programs:

  • GnuPG, which forms the heart of Gpg4win - the actual encryption software.
  • Kleopatra, the central certificate administration of Gpg4win, which ensures uniform user navigation for all cryptographic operations.
  • GNU Privacy Assistant (GPA), an alternative program for managing certificates, in addition to Kleopatra.
  • GnuPG for Outlook (GpgOL), an extension for Microsoft Outlook 2003 and 2007, which is used to sign and encrypt messages.
  • GPG Explorer eXtension (GpgEX), an extension for Windows Explorer which can be used to sign and encrypt files using the context menu.
  • Claws Mail, a full e-mail program that offers very good support for GnuPG.

Migrating / Creating a New Key

Pre-requisites

$> brew install hopenpgp-tools

Download the gpg.conf as part of duraconf - A collection of hardened configuration files for SSL/TLS services which implement the Riseup OpenPGP Best Practices

  $> wget https://raw.githubusercontent.com/ioerror/duraconf/master/configs/gnupg/gpg.conf

General recommendations / Best practices

  • create a 4096bit RSA key, with the sha512 hashing algorithm
  • Use the concept of GPG key subpairs
    • your primary key is only meant for certification / authentication purposes (in particular not for signing or encrypting). Use the --expert flag upon generation to configure it that way
  • Expiration date should be within less than two years.
    • You can always extend the key expiration as long as you still have access to the key, even after it has expired

Generating the Primary Key

Invoke gpg --gen-key with the --expert flag to expose some additional menu items. Select RSA key with

# Generate the new primary key for authentication / certification only
$> gpg --gen-key --expert
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
Your selection? 8

Make it capable only of certifying / authenticate other keys

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? s

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? e

Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? q

Select a 4096 bits key

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

Set an expiration date of 2 years – You can always extend the key expiration as long as you still have access to the key, even after it has expired. Why should I set an expiration.

Make sure to add an entry to set a calendar event to remind you about your expiration date

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 2y
Key expires at Fri Mar  1 10:14:44 2019 CET
Is this correct? (y/N) y

Set the UID (name / email) WITHOUT comment, and make sure to use a very very strong passphrase (use your favorite password manager for that like 1Password):

GnuPG needs to construct a user ID to identify your key.

Real name: Sebastien Varrette
Email address: Sebastien.Varrette@uni.lu
Comment: Primary Certification Key
You selected this USER-ID:
    "Sebastien Varrette <Sebastien.Varrette@uni.lu>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 4F156AD7 marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: Note: signatures using the MD5 algorithm are rejected
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   3  signed:  21  trust: 0-, 0q, 0n, 0m, 0f, 3u
gpg: depth: 1  valid:  21  signed:   5  trust: 11-, 0q, 0n, 3m, 7f, 0u
gpg: depth: 2  valid:   2  signed:   0  trust: 2-, 0q, 0n, 0m, 0f, 0u
gpg: next trustdb check due at 2017-03-08
pub   4096R/4F156AD7 2017-03-01 [expires: 2019-03-01]
      Key fingerprint = 1A53 FD6E 09A4 4DBA 7A9F  D72B 5D08 BCDD 4F15 6AD7
uid       [ultimate] Sebastien Varrette <Sebastien.Varrette@uni.lu>

At this point, we have a new OpenPGP (4096-bit RSA) primary key for Certifying other keys (with ID 4F156AD7 in the above case), together (eventually) with your old key (ID DD01D5C0 in my case) – use gpg -K to list them.

$> gpg -K
sec   1024D/DD01D5C0 2006-05-19
uid                  Sebastien Varrette (Falkor) <Sebastien.Varrette@imag.fr>
uid                  Sebastien Varrette <Sebastien.Varrette@uni.lu>
ssb   2048g/9BE4EF49 2006-05-19

sec   4096R/4F156AD7 2017-03-01 [expires: 2019-03-01]
uid                  Sebastien Varrette <Sebastien.Varrette@uni.lu>

You probably wish to set a primary UID for this key (assuming you defined many of them)

$> gpg --edit-key 0x4F156AD7
[...]
Secret key is available.

pub  4096R/4F156AD7  created: 2017-03-01  expires: 2019-03-01  usage: C
                     trust: ultimate      validity: ultimate
[ultimate] (1). Sebastien Varrette <Sebastien.Varrette@uni.lu>
[ultimate] (2)  Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>

# Select the default UID (from its number)
gpg> uid 1

pub  4096R/4F156AD7  created: 2017-03-01  expires: 2019-03-01  usage: C
                     trust: ultimate      validity: ultimate
[ultimate] (1)* Sebastien Varrette <Sebastien.Varrette@uni.lu>
[ultimate] (2)  Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>

# Make it primary
gpg> primary
[...]
gpg> save            # Commit your changes

Add other elligible UIDs and a photo

You probably want to complete it with additional UID (other elligible email(s)) and photos.

$> gpg --edit-key 0x4F156AD7
[...]
gpg> adduid          # Add a new UID
Real name: Sebastien Varrette
Email address: Sebastien.Varrette@gmail.com
Comment: Falkor
You selected this USER-ID:
    "Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>"
[...]
gpg> save            # Commit your changes

Prepare one (small) picture of you, keeping the image close to 240x288 and as small as possible.

$> gpg --edit-key 0x4F156AD7
[...]
gpg> addphoto       # Add a picture to your key

Pick an image to use for your photo ID.  The image must be a JPEG file.
Remember that the image is stored within your public key.  If you use a
very large picture, your key will become very large as well!
Keeping the image close to 240x288 is a good size to use.

Enter JPEG filename for photo ID: /Users/svarrette/Desktop/svarrette.jpg
Are you sure you want to use it? (y/N) y
Is this photo correct (y/N/q)? y

# Commit your changes
gpg> save

Ensure that the new key uses strong cryptography preferences.

By default, the encryption preferences specified in your public key are probably not as strong as they should be. Thus you should set stronger default security preferences (to use SHA512, AES256 and ZLIB by default) using the setpref command, i.e.:

setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

In practice:

$> gpg --edit-key 0x4F156AD7
[...]
gpg> showpref        # Show current Preferences
[ultimate] (1). Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
     Cipher: AES256, AES192, AES, CAST5, 3DES, IDEA
     Digest: SHA256, SHA1, SHA384, SHA512, SHA224
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify
[ultimate] (2)  Sebastien Varrette <Sebastien.Varrette@uni.lu>
     Cipher: AES256, AES192, AES, CAST5, 3DES, IDEA
     Digest: SHA256, SHA1, SHA384, SHA512, SHA224
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify

# Set better defaults security preferences
gpg> setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
[...]

# Check the result
gpg> showpref
[ultimate] (1)  Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
     Cipher: AES256, AES192, AES, CAST5, 3DES
     Digest: SHA512, SHA384, SHA256, SHA224, SHA1
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify
[ultimate] (2). Sebastien Varrette <Sebastien.Varrette@uni.lu>
     Cipher: AES256, AES192, AES, CAST5, 3DES
     Digest: SHA512, SHA384, SHA256, SHA224, SHA1
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, Keyserver no-modify
# Commit your changes
gpg> save

Generating separate subkeys for signing and encryption

The primary key created above is used only for certifications (i.e. signing another key), which happen infrequently. In your daily GPG usage, you need in addition subkeys for signing (e.g. signing an email message or files), encrypting (mails or files) or authenticating. It is useful to separate those purposes as one is way more important than the other.

To add a subkey (for a given purpose), the command to use when interactively editing a key is addkey (to sign only, or to encrypt only). Select a 4096 bites size, put an expiration date of no more than 18 months for these subkeys. Use again the --expert flag to specify the charactistics of the key the way you want.

$> gpg --expert --edit-key 0x4F156AD7
[...]
gpg> addkey
[...]
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
Your selection? 8
[...]
Current allowed actions: Sign Encrypt

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? e
Current allowed actions: Sign
[...]
Your selection? q
[...]
What keysize do you want? (2048) 4096
[...]
Key is valid for? (0) 18m
Key expires at Thu Aug 23 16:45:07 2018 CEST
Is this correct? (y/N) y
Really create? (y/N) y
[...]
gpg> save

At the end, you should see two subkeys as follows (notice the usage of each subkeys sub):

$> gpg --expert --edit-key 0x4F156AD7
[...]
pub  4096R/4F156AD7  created: 2017-03-01  expires: 2019-03-01  usage: C
                     trust: ultimate      validity: ultimate
sub  4096R/162C95D4  created: 2017-03-01  expires: 2018-08-23  usage: S
sub  4096R/354B109D  created: 2017-03-01  expires: 2018-08-23  usage: E
sub  4096R/180E98A5  created: 2017-03-01  expires: 2018-08-23  usage: A
[ultimate] (1). Sebastien Varrette <Sebastien.Varrette@uni.lu>
[ultimate] (2)  Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
[ultimate] (3)  [jpeg image of size 3075]

Create a revocation certificate for the NEW key

If you forget your passphrase or if your [master] private key is compromised or lost, the only hope you have is to wait for the key to expire (this is not a good solution), or to activate your revocation certificate by publishing it to the keyservers. Doing this will notify others that this key has been revoked.

Good point is that a revoked key can still be used to verify old signatures, or decrypt data (if you still have access to the private key), but it cannot be used to encrypt new messages to you. /!\ WARNING: This is important, don’t skip this step!

A revocation certificates comes with a reason, so when a new key pair is created, generic revocation certificates for that key pair should be generated and securely stored. It is recommended that a certificate is generated for each appropriate revocation reason type:

  • No reason specified
  • Key has been compromised (your normally need to set a description message)
  • Key is no longer used

Note: the reason “Key is superseded” is not appropriate for a new key since it is not possible to know which key will replace it.

Again, generic revocation certificates need to be stored safe but securely until needed.

You need to operate and save these files in an encrypted vault (Use Knox / encrypted sparsebundle / encFS / encrypted USB drive / CipherShed / whatever)

$> cd /path/to/encrypted/vault
$> mkdir gpg && cd gpg
$> gpg --output revoke-4F156AD7-no-reason.asc      --armor --gen-revoke 4F156AD7
$> gpg --output revoke-4F156AD7-compromised.asc    --armor --gen-revoke 4F156AD7
$> gpg --output revoke-4F156AD7-no-longer-used.asc --armor --gen-revoke 4F156AD7

Example of output:

$> gpg --output revoke-4F156AD7-no-reason.asc --armor --gen-revoke 4F156AD7
sec  4096R/4F156AD7 2017-03-01 Sebastien Varrette <Sebastien.Varrette@uni.lu>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 0
Enter an optional description; end it with an empty line:
>
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y

You need a passphrase to unlock the secret key for
user: "Sebastien Varrette <Sebastien.Varrette@uni.lu>"
4096-bit RSA key, ID 4F156AD7, created 2017-03-01

Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

Backing Up Public, Secret Keys and ownertrust

$> cd /path/to/encrypted/vault/gpg
$> gpg -a --export 4F156AD7 > gpg-4F156AD7.key.pub          # Export public key
$> gpg -a --export-secret-keys 4F156AD7 > gpg-4F156AD7.key  # Export private key
$> gpg --export-ownertrust > gpg-4F156AD7-ownertrust.txt    # Export ownertrust

Note: later on, if you need to import the secret key (which contains the public key) and ownertrust, use:

$> gpg --import gpg-4F156AD7.key
$> gpg --import-ownertrust gpg-4F156AD7-ownertrust.txt

Export your public key

$> cd ~/.ssh
$> mkdir gpg && gpg
$> gpg -a --export 4F156AD7 > 4F156AD7-sebastien.varrette@uni.lu.asc

Web Of Trust: cross-sign the new key with the old key

Since we’ve generated an entirely new key, we need to form a trust link between the old and new keys by cross-signing. If people have your old key, this helps them trust that the new key was generated by you.

$> gpg --default-key <old_key> --sign-key <new_key>  # Sign the new key with the old one
$> gpg --default-key <new_key> --sign-key <old_key>  # Sign the old key with the new one

In practice:

# <new_key> = 4F156AD7   <old_key> = DD01D5C0
$> gpg --default-key  DD01D5C0 --sign-key 4F156AD7
$> gpg --default-key  4F156AD7 --sign-key  DD01D5C0

Use the sks keyserver pool with secure connections as default keyserver

Quoting riseup tutorial:

Most OpenPGP clients come configured with a single, specific keyserver. This is not ideal because if the keyserver fails, or even worse, if it appears to work but is not functioning properly, you may not receive critical key updates. Not only is this a single point of failure, it is also a prime source of leaks of relationship information between OpenPGP users, and thus an attack target. Therefore, we recommend using the sks keyservers pool. The machines in this pool have regular health checks to ensure that they are functioning properly. If a server is not working well, it will be removed automatically from the pool.

$> mkdir ~/.gnupg/certs
$> cd ~/.gnupg/certs
$> wget https://sks-keyservers.net/sks-keyservers.netCA.pem
$> wget https://sks-keyservers.net/sks-keyservers.netCA.pem.asc

Then update ~/.gnupg/gpg.conf as follows:

#-----------------------------
# keyserver
#-----------------------------

# This is the server that --recv-keys, --send-keys, and --search-keys will
# communicate with to receive keys from, send keys to, and search for keys on
keyserver hkps://hkps.pool.sks-keyservers.net

# Provide a certificate store to override the system default
# Get this from https://sks-keyservers.net/sks-keyservers.netCA.pem
# :keyserver-options ca-cert-file=/usr/local/etc/ssl/certs/hkps.pool.sks-keyservers.net.pem
keyserver-options ca-cert-file=~/.gnupg/certs/sks-keyservers.netCA.pem

Note the complete file is available on Github.

Export and Uploading your new and old keys to key server

Export your public key(s)

$> mkdir ~/.ssh/gpg
$> cd  ~/.ssh/gpg
$> gpg -a --export 4F156AD7 > 4F156AD7-sebastien.varrette@uni.lu.asc

Upload your new and old keys to the [sks / MIT] key servers:

$> gpg --send-keys A403AC45DD01D5C0 5D08BCDD4F156AD7
$> gpg --keyserver pgp.mit.edu --send-keys A403AC45DD01D5C0 5D08BCDD4F156AD7

[optional] Transition file

You might wish also to create a transition statement file signed with both keys. Sample migration document.

$> vim transition-statement.md
# Embed signature using the OLD key
$> gpg --digest-algo SHA512 --default-key A403AC45DD01D5C0 --clearsign transition-statement.md
$> mv transition-statement.md.asc DD01D5C0-transition-statement.md.asc
# Embed signature using the NEW key
$> gpg --clearsign transition-statement.md
$> mv transition-statement.md.asc  4F156AD7-transition-statement.md.asc

The created signed files are available on Github.

Set default to the new key

The default key on the keyring needs to be changed from the old key to the new. This will ensure that all future signatures will use by default the new key.

To make the new key the default, set the default-key in the ~/.gnupg/gpg.conf configuration file.

Expiring and/or Revoking The Old Key

We need to tell the world to not use the old key anymore. There are two ways to do this:

  1. Wait for the expiration date to be reached. It tells the world not to use the key anymore but that you still control the secret parts.
  2. Revoke the (old) key. This tells the world to not trust the key anymore.

Just as we created (in advance) revocation certificates for the new key, you shall create a revocation certificate for your old key with reason “Key is superseded” – place as comment “Superseded by 0x<NEW KEY ID>

$> gpg --output revoke-DD01D5C0-superseed-by-4F156AD7.asc --armor --gen-revoke DD01D5C0
sec  1024D/0xA403AC45DD01D5C0 2006-05-19 Sebastien Varrette (Falkor) <Sebastien.Varrette@imag.fr>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 2
Enter an optional description; end it with an empty line:
> Superseded by 0x5D08BCDD4F156AD7
>
Reason for revocation: Key is superseded
Superseded by 0x5D08BCDD4F156AD7
Is this okay? (y/N) y

Now, import the revocation certificate and send it to the public key server(s):

$> gpg --import revoke-DD01D5C0-superseed-by-4F156AD7.asc
$> gpg --send-keys A403AC45DD01D5C0
$> gpg --keyserver pgp.mit.edu  --send-keys A403AC45DD01D5C0

Removing the Primary Key / Prepare Laptop Key

we can separate the primary key (made for certification only) from the 3 subkeys and gain some security. This set is often refered to as “laptop keys”, as you can keep them on your laptop while the primary key secret remains safely locked away.

Unfortunately, the process for removing the primary key is non-obvious. So let’s go:

First backup everything:

$> cd /path/to/encrypted/vault/gpg
$> mkdir -p backup/.gnupg
$> cd backup
$> rsync -avzu ~/.gnupg/*.gpg .gnupg

note: Initial state:

$> gpg -k 4F156AD7     # Public part of the key
pub   4096R/0x5D08BCDD4F156AD7 2017-03-01 [expires: 2019-03-01]
      Key fingerprint = 1A53 FD6E 09A4 4DBA 7A9F  D72B 5D08 BCDD 4F15 6AD7
uid                 [ultimate] Sebastien Varrette <Sebastien.Varrette@uni.lu>
uid                 [ultimate] Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
uid                 [ultimate] [jpeg image of size 3075]
sub   4096R/0x28E10E61162C95D4 2017-03-01 [expires: 2018-08-23]
sub   4096R/0xEE2047E4354B109D 2017-03-01 [expires: 2018-08-23]
sub   4096R/0x5BE73686180E98A5 2017-03-01 [expires: 2018-08-23]

$> gpg -K 4F156AD7     # Private part of the key
sec   4096R/0x5D08BCDD4F156AD7 2017-03-01 [expires: 2019-03-01]
      Key fingerprint = 1A53 FD6E 09A4 4DBA 7A9F  D72B 5D08 BCDD 4F15 6AD7
uid                            Sebastien Varrette <Sebastien.Varrette@uni.lu>
uid                            Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
uid                            [jpeg image of size 3075]
ssb   4096R/0x28E10E61162C95D4 2017-03-01 [expires: 2018-08-23]
ssb   4096R/0xEE2047E4354B109D 2017-03-01 [expires: 2018-08-23]
ssb   4096R/0x5BE73686180E98A5 2017-03-01 [expires: 2018-08-23]

Export just the subkey secrets:

$> cd /path/to/encrypted/vault/gpg
$> mkdir subkeys && cd subkeys
$> gpg -a --export-secret-subkeys 4F156AD7 > gpg-4F156AD7_subkeys.key

Then delete the entire (both primary and subkeys) secret part of your key from the keyring:

$> gpg --delete-secret-keys 4F156AD7
sec  4096R/0x5D08BCDD4F156AD7 2017-03-01 Sebastien Varrette <Sebastien.Varrette@uni.lu>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

This leaves us with the public part in ~/.gnupg/pubring.gpg unchanged, but the private part empty

$> gpg -k 4F156AD7     # Public part of the key
pub   4096R/0x5D08BCDD4F156AD7 2017-03-01 [expires: 2019-03-01]
      Key fingerprint = 1A53 FD6E 09A4 4DBA 7A9F  D72B 5D08 BCDD 4F15 6AD7
uid                 [ultimate] Sebastien Varrette <Sebastien.Varrette@uni.lu>
uid                 [ultimate] Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
uid                 [ultimate] [jpeg image of size 3075]
sub   4096R/0x28E10E61162C95D4 2017-03-01 [expires: 2018-08-23]
sub   4096R/0xEE2047E4354B109D 2017-03-01 [expires: 2018-08-23]
sub   4096R/0x5BE73686180E98A5 2017-03-01 [expires: 2018-08-23]

$> gpg -K 4F156AD7     # Private part
gpg: error reading key: No secret key

Now re-import just the subkeys previously exported (i.e. not the full secret key from earlier):

$> gpg --import gpg-4F156AD7_subkeys.key
gpg: key 0x5D08BCDD4F156AD7: secret key imported
gpg: key 0x5D08BCDD4F156AD7: "Sebastien Varrette <Sebastien.Varrette@uni.lu>" 2 new signatures
gpg: Total number processed: 1
gpg:         new signatures: 2
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

You can check that everything is fine i.e. that you have now laptop keys:

$>gpg -K 4F156AD7
sec#  4096R/0x5D08BCDD4F156AD7 2017-03-01 [expires: 2019-03-01]
      Key fingerprint = 1A53 FD6E 09A4 4DBA 7A9F  D72B 5D08 BCDD 4F15 6AD7
uid                            Sebastien Varrette <Sebastien.Varrette@uni.lu>
uid                            Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
uid                            [jpeg image of size 3075]
ssb   4096R/0x28E10E61162C95D4 2017-03-01 [expires: 2018-08-23]
ssb   4096R/0xEE2047E4354B109D 2017-03-01 [expires: 2018-08-23]
ssb   4096R/0x5BE73686180E98A5 2017-03-01 [expires: 2018-08-23]

Notice the # after sec: this denotes that the primary key secret is not in your keyring.

Change the passphrase protecting the subkeys – This way if your (new) subkey passphrase is compromised, the primary master key will remain safe.

$> gpg --edit-key 4F156AD7  passwd

In Case of Emergency / Primary Key operations

References:

To sign someone other keys or to create or revoke a SubKey, the Primary Master Secret Key is needed, for this reason it is suggested to use a temporary keyring, in a safe environment.

Importing the primary secret key into a temporary (secondary) keyring

To import from the safe storage medium / encrypted vault back to a temporary (secondary) keyring:

$> cd /path/to/encrypted/vault
# Assuming gpg-4F156AD7.key private primary key export is here
$> mkdir tmp-keyring
$> cd tmp-keyring
$> cp -r ~/.gnupg/certs .

# Import the secret key into a temporary keyring ./tmp-{ public | private }-kr.gpg
$> gpg --no-default-keyring \
       --keyring ./tmp-public-kr.gpg --secret-keyring ./tmp-private-kr.gpg --trustdb-name ./tmp-trustdb.gpg \
       --import ../gpg-4F156AD7.key

You might wish to create a wrapper for the secondary keyring, typically as follows:

#!/bin/bash
# /path/to/encrypted/vault/tmp-keyring/tmpgpg

gpg --no-default-keyring --keyring ./tmp-public-kr.gpg --secret-keyring ./tmp-private-kr.gpg --trustdb-name ./tmp-trustdb.gpg $@

Use Case 1: Sign someone else’s GPG Key

# Retrieve the key that needs to be signed
$> gpg --no-default-keyring \
       --keyring ./tmp-public-kr.gpg --secret-keyring ./tmp-private-kr.gpg --trustdb-name ./tmp-trustdb.gpg \
       --keyserver pgp.mit.edu --recv-keys <fingerprint>
# OR
$> ./tmpgpg --keyserver pgp.mit.edu --recv-keys <fingerprint>    # adpat fingerprint accordingly

# Check if the key has been correctly imported:
$> ./tmpgpg -k <fingerprint>

# Sign the Key
$> ./tmpgpg --sign-key --ask-cert-level <fingerprint>

# Check that it worked as expected
$> ./tmpgpg --list-sigs <fingerprint>

# Upload back the signed key to the keyserver
$> ./tmpgpg --keyserver pgp.mit.edu --send-key <fingerprint>   # send to pgp.lit.edu
$> ./tmpgpg --keyserver hkps://hkps.pool.sks-keyservers.net --keyserver-options ca-cert-file=./certs/sks-keyservers.netCA.pem --send-keys <fingerprint>

Example:

# === UL HPC Admin Group ===
# S. Varrette       C. Parisot        H. Cartiaux        V. Plugaru        S. Diehl
# 5D08BCDD4F156AD7  07FEA8BA69203C2D  37183CEF550DF40B   3F3242C5B34D98C2  6429C2514EBC4737
~
$> for id in  07FEA8BA69203C2D  37183cef550df40b   3F3242C5B34D98C2  6429C2514EBC4737; do \
      ./tmpgpg --keyserver pgp.mit.edu --recv-keys $id; \
      ./tmpgpg --sign-key --ask-cert-level $id; \
   done
$> ./tmpgpg -k | grep pub
./tmp-public-kr.gpg
pub   4096R/0x5D08BCDD4F156AD7 2017-03-01 [expires: 2019-03-01]
pub   4096R/0x07FEA8BA69203C2D 2017-03-09 [expires: 2019-03-09]
pub   4096R/0x37183CEF550DF40B 2011-08-01 [expires: 2021-07-29]
pub   4096R/0x3F3242C5B34D98C2 2017-03-09 [expires: 2019-03-09]
pub   4096R/0x6429C2514EBC4737 2017-01-06 [expires: 2027-01-01]

$> ./tmpgpg --list-sigs

# Send them
$> for id in  07FEA8BA69203C2D  37183cef550df40b   3F3242C5B34D98C2  6429C2514EBC4737; do \
      ./tmpgpg --keyserver pgp.mit.edu --send-key $id; \
       ./tmpgpg --keyserver hkps://hkps.pool.sks-keyservers.net --keyserver-options ca-cert-file=./certs/sks-keyservers.netCA.pem --send-keys  $id; \
   done

Use Case 2: Extending the lifetime of a key

The point of setting an expiration date for all of your keys is to have them actually expire if you lose access to the master keys or the revokation key. Besides, checking your keys at least once per year can is a good practice that probably enhances your security.

$> ./tmpgpg --edit-key <fingerprint>
gpg> expire
[...]
gpg> save

Prologue: securely delete the temporary (secondary) keyring

Once you have finished, if the temporary wallet is written in a non-volatile filesystem, it is mandatory to remove temporary files in the safest way from the media where all these operation are made. For this reason, it is suggested to use shred (or srm on Mac OS X, to be installed with brew install srm) to overwrite the file multiple times using patterns chosen to maximize destruction of the residual data.

# Linux
$> shred -vfzu -n 10 ./tmp-*

# Mac OS X
$> brew install srm
$> brew link --force homebrew/dupes/srm
$> srm -v ./tmp-*

Now you can safely unmount your vault.

Key checks

According to RFC4880: “V3 keys are deprecated” so you have to make sure your keys are OpenPGPv4.

$> gpg --export-options export-minimal --export '4F156AD7' | gpg --list-packets |grep version
	version 4, algo 1, created 1488361903, expires 0
	version 4, created 1488379876, md5len 0, sigclass 0x13
	version 4, created 1488366555, md5len 0, sigclass 0x13
	version 4, created 1488374686, md5len 0, sigclass 0x13
	version 4, algo 1, created 1488378396, expires 0
	version 4, created 1488378396, md5len 0, sigclass 0x18
	version 4, algo 1, created 1488379557, expires 0
	version 4, created 1488379557, md5len 0, sigclass 0x18
	version 4, algo 1, created 1488381897, expires 0
	version 4, created 1488381897, md5len 0, sigclass 0x18

Etc.

Keybase.io

Keybase.io aims to make life with GPG easier. It does a really good job but it encourages a bad behavior in key management, i.e. by default, it creates and stores a private key on their server. We can never truly verify the condition of their server so a Keybase-hosted private key should always be considered untrustworthy. So we will configure Keybase.io to just use our existing key

Install keybase:

$> brew cask install keybase

You can then configure the completion files on your system:

Now you can select your (local) gpg key and import the public key to Keybase.io (thus using the --no-import option).

keybase pgp select --no-import 4F156AD7
#    Algo    Key Id             Created   UserId
=    ====    ======             =======   ======
1    4096R   5D08BCDD4F156AD7             Sebastien Varrette <Sebastien.Varrette@uni.lu>, Sebastien Varrette <Sebastien.Varrette@gmail.com>
Choose a key: 1
▶ INFO Bundle unlocked: 5D08BCDD4F156AD7
▶ INFO Generated new PGP key:
▶ INFO   user: Sebastien Varrette (Falkor) <Sebastien.Varrette@gmail.com>
▶ INFO   4096-bit RSA key, ID 5D08BCDD4F156AD7, created 2017-03-01
▶ INFO Key 5D08BCDD4F156AD7 imported

Adding Trust Using Public Account

# prove that the twitter account @svarrette really belongs to you
$> keybase prove twitter svarrette

# repeat for github, your web site etc...
$> keybase prove github Falkor
$> keybase prove web https://varrette.gforge.uni.lu

GPG CLI Usage

$> gpg ---gen-key                                        # Generate your PGP key
$> gpg ---list-keys [pattern]                            # List available PGP key(s)
$> gpg ---keyserver pgp.mit.edu ---search-keys <pattern> # Search \& Import
$> gpg ---keyserver pgp.mit.edu ---recv-keys <ID>        # Import
$> gpg ---keyserver pgp.mit.edu ---send-keys <ID>        # Export to server

/!\ IMPORTANT: sending encrypted mails to user@domain.org assumes that you trust his key, i.e. that you sign (after careful check) this key (using GPG Keychain / GPA).

$> gpg [-K] ---fingerprint <mail>                  # Get (with -K) / Check fingerprint
$> gpg ---sign-key ---ask-cert-level <ID>          # Sign Key <ID> AFTER check
$> gpg ---keyserver pgp.mit.edu ---send-keys <ID>  # Send back signed key

Now if you want to encrypt / decrypt / digitally sign files:

$> gpg ---encrypt [-r <recipient>] <file>     # => <file>.gpg
$> rm -f <file>    # /!\ WARNING: encryption does not delete the input (clear-text) file

$> gpg ---decrypt <file>.gpg           # Decrypt PGP encrypted file
$> gpg ---armor ---detach-sign <file>  # Generate signature file <file>.asc

GPG Keychain / Keyring

  • Linux / Mac OS: ~/.gnupg/
  • Windows: C:\\Documents and Settings\<LOGIN>\Application Data\gnupg\

Using GPG within git

  • Sign tags using your GPG key with the -s option
    • add Signed-off-by line by the committer using -s : git commit -s [...]
    • GPG sign commit with -S: git commit -s -S [...]
    • tag sign: git tag -s <name>
  • Assumes that you have configured git with your GPG signing key ID. Example below:
[user]
    name = Sebastien Varrette
    email = Sebastien.Varrette@uni.lu
    signingkey = 0xDD01D5C0