This article describes how I bootstrap my personal GPG keys. Extra security measurements can be taken when using GPG keys for mission-critical purposes such as initializing HashiCorp Vault KMS.
Tools
- GnuPG 2.0.x
- 1 USB key (or CD/DVD) for the OS (preferably a write-protected USB key like this)
- 2 USB keys or more for backing up the generated GPG keys
- 1 USB key to transfer the subkeys into day-to-day machines
A Secure Environment
Ideally, the whole key generation process should be performed on a completely offline machine booting a Live CD version of an open-source OS. One of the example documents of this practice can be found here.
Having said that, however, computer systems are complex. Even if we trust an open-source OS, we can only have limited confidence in the underlying hardware. There are some attempts at gaining more trust on the assembling process and the firmware. Even then, we still don’t have a clear picture of what is underneath. I won’t go any further on this topic, but keep that in mind.
Personally, I use CentOS on a “normal” laptop and I think it is good enough in my case. And just to be on the safe side, I disable all the network interfaces and remove the SSD. Tails is a nice Linux distro for security and privacy but it has some drawbacks: secure boot is not well supported (yet?) and it comes with modern (2.1.x) GPG (I’ll explain later). CentOS 7 LiveGNOME, however, supports secure boot out-of-the-box and has the right stable (2.0.x) GPG.
The first step is obtaining and verifying the CentOS 7 LiveGNOME ISO file, putting it into a (non-writable) bootable media and booting the system. While verifying the ISO file, you will notice that we have a chicken-and-egg problem: we need a trusted machine with GPG installed! That is another problem you have to think of if you plan to generate GPG keys for mission-critical purposes.
Generating GPG Keys
In this section, I will show you how to generate a GPG master key and several subkeys. The master key is kept completely offine and is only used to certify the subkeys. Each of the subkeys only serves one purpose: encrypt, sign or authentication.
First of all, there are some changes and some “features” (1, 2, 3, 4) in GnuPG 2.1.x that make it unreliable. As I mentioned above, CentOS 7 LiveGNOME comes with GPG 2.0.x, which is perfect for this task. You can use any open-source OS you like, just make sure that it has GPG 2.0.x installed.
By default, the String-to-Key (S2K) function is used to derive a key from the passphrase. That key is used to encrypt your GPG private keys at rest. From the GnuPG man page:
--s2k-cipher-algo name
Use name as the cipher algorithm used to protect secret keys. The defau-
lt cipher is AES128. This cipher is also used for conventional encrypti-
on if --personal-cipher-preferences and --cipher-algo is not given.
--s2k-digest-algo name
Use name as the digest algorithm used to mangle the passphrases. The de-
fault algorithm is SHA-1.
--s2k-mode n
Selects how passphrases are mangled. If n is 0 a plain passphrase (whic-
h is not recommended) will be used, a 1 adds a salt to the passphrase a-
nd a 3 (the default) iterates the whole process a number of times (see
--s2k-count). Unless --rfc1991 is used, this mode is also used for conv-
entional encryption.
--s2k-count n
Specify how many times the passphrase mangling is repeated. This value
may range between 1024 and 65011712 inclusive. The default is inquired
from gpg-agent. Note that not all values in the 1024-65011712 range are
legal and if an illegal value is selected, GnuPG will round up to the
nearest legal value. This option is only meaningful if --s2k-mode is 3.
The default s2k-mode
is 3
, which is Iterated and Salted S2K. The default cipher and digest algorithms are AES128
and SHA1
, respectively. I prefer to use these values instead:
--s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-count 65011712
Additionally, personal-cipher-preferences
and personal-digest-preferences
can be changed to AES256
and SHA512
(however, it may not be compatible with other software) Those parameters are used when encrypting or signing with your GPG keys.
Generating the Master Key
Some OSes have both versions of GPG: gpg
for 1.x and gpg2
for 2.x. Again, make sure that you use the correct 2.0.x version. Here are the steps to generate a new GPG master key:
- Open terminal
- Change
REAL_NAME
,EMAIL
,VALID_FOR
, etc. to the correct ones:
Generating the Subkeys
Encryption Subkey
Signing Subkey
Authentication Subkey
The string after echo
contains the answers that you would normally input when creating subkeys manually. For example:
gpg --expert --edit-key "$EMAIL"
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)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
Your selection? 8
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign 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 Encrypt Authenticate
Current allowed actions: 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 Encrypt Authenticate
Current allowed actions:
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
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) 1y
Key expires at Fri 10 Aug 2018 10:32:24 PM EDT
Is this correct? (y/N) y
Really create? (y/N) y
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.
sec rsa4096/0x608641233323A2E0
created: 2017-08-11 expires: 2020-08-10 usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/0xB0119B677632552F
created: 2017-08-11 expires: 2018-08-11 usage: E
ssb rsa4096/0x0C756A11735E30D9
created: 2017-08-11 expires: 2018-08-11 usage: S
ssb rsa4096/0x27D24F72AC456F15
created: 2017-08-11 expires: 2018-08-11 usage: A
[ultimate] (1). John Doe <[email protected]>
Backup
Plug in one of the backup USB keys and change the current directory to its root. Then generate the revocation certificate:
You can see what hash algorithm is used by the --list-packets
flag, digest algo 10
means SHA512
:
After that backup your keys:
The whole gpg
folder in /tmp
should also be copied to the USB key. The same steps should be performed to backup the GPG keys to the remaining USB keys. Those USB keys should be kept completely offline at separate locations.
Export
Plug in the USB used for transferring the subkeys to day-to-day machines and export the subkey:
The subkeys can be imported into the GPG keyring on your day-to-day machines:
Listing your freshly generated keys in the GPG keyring:
You’ll notice something like sec# rsa4096/...
, the #
means the private key of the master key is not present on the machine.
Extra
To change the algorithms of your existing GPG keys, a changing passphrase operation needs to be performed, even if the same old passphrase is re-used:
To find out which algorithms are currently used to protect your GPG keys (won’t work with “modern” (2.1.x) GPG):
From RFC4880, algo: 9
means AES256
and hash: 10
means SHA512
.
References
PGP
- https://alexcabal.com/creating-the-perfect-gpg-keypair/
- https://pthree.org/2015/11/19/your-gnupg-private-key/
- https://riseup.net/en/security/message-security/openpgp/best-practices
- https://wiki.debian.org/Subkeys
- https://help.ubuntu.com/community/GnuPrivacyGuardHowto
- https://fedoraproject.org/wiki/Creating_GPG_Keys
- https://tools.ietf.org/html/rfc4880
- https://www.tylerburton.ca/2015/04/increasing-the-protection-of-your-stored-pgp-key/
- https://wiki.ubuntu.com/SecurityTeam/GPGMigration
- https://debian-administration.org/users/dkg/weblog/48
- https://davesteele.github.io/gpg/2014/09/20/anatomy-of-a-gpg-key/
- http://www.openpgp-schulungen.de/scripte/keygeneration/key-generation.sh
- https://spin.atomicobject.com/2013/10/23/secure-gpg-keys/
- https://spin.atomicobject.com/2013/11/24/secure-gpg-keys-guide/
Other
- https://blog.josefsson.org/2016/11/03/why-i-dont-use-2048-or-4096-rsa-key-sizes/
- https://www.yubico.com/2015/02/big-debate-2048-4096-yubicos-stand/
- https://blog.filippo.io/on-keybase-dot-io-and-encrypted-private-key-sharing/
- https://blog.filippo.io/giving-up-on-long-term-pgp/
- http://www.issihosts.com/haveged/
- https://wiki.debian.org/OpenPGP/CleanRoomLiveEnvironment
- https://dev.guardianproject.info/projects/psst/wiki/CleanRoom
- https://gist.github.com/abeluck/3383449