Since version 2.1.7 (August 2015), we can use GPG to encrypt data by Curve25519.1 This gives us everything we need to have a poison-free set of elliptic curve GPG keys.
Elliptic curves have actually been around for a while, but only in the past few years have they actually gained a bit of traction. Here’s why you might want to use elliptic curve cryptography over traditional schemes:
https://www.gniibe.org/memo/software/gpg/keygen-25519.html↩︎
You should note that elliptic curve cryptography is not resilient to quantum attacks; in fact, there reasons to believe that it is more susceptible to a Shor’s algorithm derivative attack than traditional schemes like RSA4.
sh-4.3$ gpg2 --expert --full-gen-key
gpg (GnuPG) 2.1.15; Copyright (C) 2016 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.
gpg: keybox '/tmp/GNUPGHOME/pubring.kbx' created
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)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
Your selection? 11
Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Sign Certify
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? S
It’s not necessary for the primary key to be able to sign, because you should be using a subkey for that.
Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Certify
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? Q
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
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)
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Nick Hu
Email address: curvygpg@example.com
Comment:
You selected this USER-ID:
"Nick Hu <curvygpg@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
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: /tmp/GNUPGHOME/trustdb.gpg: trustdb created
gpg: key 3DC7006A1FAF2C79 marked as ultimately trusted
gpg: directory '/tmp/GNUPGHOME/openpgp-revocs.d' created
gpg: revocation certificate stored as '/tmp/GNUPGHOME/openpgp-revocs.d/DA5A5DBBBC67450CF41988013DC7006A1FAF2C79.rev'
public and secret key created and signed.
pub ed25519 2016-09-03 [C]
DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
uid Nick Hu <curvygpg@example.com>
Now we need to generate a couple of subkeys, which will actually be used day-to-day.
There’s a mechanism in GPG keys whereby we can create additional keys which are associated with the key we made above (a subkey), and use these keys to delegate responsibility and reduce the attack surface for our keys:
sh-4.3$ gpg2 --expert --edit-key DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
gpg (GnuPG) 2.1.15; Copyright (C) 2016 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.
Secret key is available.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
sec ed25519/3DC7006A1FAF2C79
created: 2016-09-03 expires: never usage: C
trust: ultimate validity: ultimate
[ultimate] (1). Nick Hu <curvygpg@example.com>
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? 10
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
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 Mon 03 Sep 2018 20:45:45 BST
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 ed25519/3DC7006A1FAF2C79
created: 2016-09-03 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/9DCBF96231D424AA
created: 2016-09-03 expires: 2018-09-03 usage: S
[ultimate] (1). Nick Hu <curvygpg@example.com>
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? 12
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1
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 Mon 03 Sep 2018 20:46:04 BST
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 ed25519/3DC7006A1FAF2C79
created: 2016-09-03 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/9DCBF96231D424AA
created: 2016-09-03 expires: 2018-09-03 usage: S
ssb cv25519/5B0632223A287797
created: 2016-09-03 expires: 2018-09-03 usage: E
[ultimate] (1). Nick Hu <curvygpg@example.com>
Now we’ve made two keys; one for signing, and one for encryption.
While we’re at it, let’s update the key to have stronger hash preferences:
gpg> setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
Set preference list to:
Cipher: AES256, AES192, AES, CAST5, 3DES
Digest: SHA512, SHA384, SHA256, SHA224, SHA1
Compression: ZLIB, BZIP2, ZIP, Uncompressed
Features: MDC, Keyserver no-modify
Really update the preferences? (y/N) y
sec ed25519/3DC7006A1FAF2C79
created: 2016-09-03 expires: never usage: C
trust: ultimate validity: ultimate
ssb ed25519/9DCBF96231D424AA
created: 2016-09-03 expires: 2018-09-03 usage: S
ssb cv25519/5B0632223A287797
created: 2016-09-03 expires: 2018-09-03 usage: E
[ultimate] (1). Nick Hu <curvygpg@example.com>
gpg> save
Let’s create a backup5 of our private and public keys:
sh-4.3$ gpg2 --export-secret-keys --armor curvygpg@example.com > \<curvygpg@example.com\>.private.gpg-key
sh-4.3$ gpg2 --export --armor curvygpg@example.com > \<curvygpg@example.com\>.public.gpg-key
Now we can take the secret key of the primary key off our keyring, storing our backup safely away elsewhere:
sh-4.3$ gpg2 -K
/tmp/GNUPGHOME/pubring.kbx
--------------------------
sec ed25519 2016-09-03 [C]
DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
uid [ultimate] Nick Hu <curvygpg@example.com>
ssb ed25519 2016-09-03 [S] [expires: 2018-09-03]
ssb cv25519 2016-09-03 [E] [expires: 2018-09-03]
sh-4.3$ gpg2 --with-keygrip --list-key
/tmp/GNUPGHOME/pubring.kbx
--------------------------
pub ed25519 2016-09-03 [C]
DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
Keygrip = D0A34F5F67D20AEDF13C622CECC4FAB2F40234A9
uid [ultimate] Nick Hu <curvygpg@example.com>
sub ed25519 2016-09-03 [S] [expires: 2018-09-03]
Keygrip = BF0956A2E685CCA56C5419EFC6049FE80754BCF1
sub cv25519 2016-09-03 [E] [expires: 2018-09-03]
Keygrip = FED066924AD46538BCF3D90A474F6C5F0980AF3A
sh-4.3$ rm $GNUPGHOME/private-keys-v1.d/D0A34F5F67D20AEDF13C622CECC4FAB2F40234A9.key
sh-4.3$ gpg2 -K
/tmp/GNUPGHOME/pubring.kbx
--------------------------
sec# ed25519 2016-09-03 [C]
DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
uid [ultimate] Nick Hu <curvygpg@example.com>
ssb ed25519 2016-09-03 [S] [expires: 2018-09-03]
ssb cv25519 2016-09-03 [E] [expires: 2018-09-03]
Note the sec#
difference after we remove the private key
- this means GPG has no secret key available for our primary key
now.
The environment variable GNUPGHOME
is used to override
directory where GPG looks for keys and configs; throughout the above,
I’ve set it to a temporary directory to create an example key to play
with.
So, in the end, we have three keys: a primary key with the Certify capability, a subkey with the Sign capability, and another subkey with the Encrypt capability. Let’s call the keys C, S and E for short.
The secret key of C should be kept offline - never transmit it over the internet, never print it in unprotected (no password) form6, and don’t keep it stored on your laptop (as it could be stolen) - keep it on an encrypted USB drive in a secure location; maybe even consider a m-of-n scheme. We don’t set an expiry for this key, because if someone else gets it, it’s essentially game over anyway. If this key is compromised, you need to rebuild your web of trust. The only time this key comes out is to sign other people’s keys at keysigning parties: to build your web of trust.
We can be a bit more liberal with S and E, and we keep their private keys on whatever device we’re using because these keys are necessary for day-to-day usage. The secret key of S is used to sign data, which can then be verified by the public key of S, and the secret key of E is used to decrypt data that is encrypted with the public key of E.
S and E are subkeys of
C; anyone can see this association, and when the public
keys are pushed to a keyserver with
gpg2 --send-keys DA5A5DBBBC67450CF41988013DC7006A1FAF2C79
the entire key is pushed as a whole, including subkeys. To emphasise, if
you did gpg2 --send-keys <subkeyid>
, GPG will tell
you it’s sending key 3DC7006A1FAF2C79
- i.e. the last 16
characters of the fingerprint of the public key of C,
the primary key.
Querying a keyserver, my actual public key has fingerprints which look like this:
Search results for '0x5e8e74ceb831fe6e'
Type bits/keyID cr. time exp time key expir
pub 256E/B831FE6E 2016-08-19
uid Nick Hu <me@nickhu.co.uk>
sig sig3 B831FE6E 2016-08-19 __________ __________ [selfsig]
sub 256E/DF631330 2016-08-19
sig sbind B831FE6E 2016-08-19 __________ 2018-08-19 []
sub 256E/B2C249C8 2016-08-19
sig sbind B831FE6E 2016-08-19 __________ 2018-08-19 []
sub 256e/25469F20 2016-08-19
sig sbind B831FE6E 2016-08-19 __________ 2018-08-19 []
You can see the public key for my primary key, and three subkeys, as the subkeys are bound to the primary key. It’s not semantically valid to think of the public key of a subkey without the public key of its primary key.
The reason we diminish the responsibility of the primary key is to reduce the risk of it being compromised; keysigning is a relatively rare operation, so we can take on the inconvenience of having to dig out our secure USB drive when we need to do it. In the event of any of the subkeys being compromised, we can use the primary key to generate a revocation certificate for just the subkey(s), and send that to the keyservers. This declares to the world that the subkey(s) in question should never be used again - signatures made after the date of the revocation should be considered invalid, and encrypting against a revoked key provides no security at all. Because our primary key is still safe, we do not lose our foothold in the web of trust7, and we can just generate new subkeys for signing and encryption without catastrophic consequence.
It’s good practice to set an expiry date on your subkeys; it shows to everyone that your keys are up to date, and forces you to keep your GPG knowledge relatively fresh. Expiry dates can be changed with the private key, so set yourself a reminder a month in advance of your subkeys expiring to update the expiry date and republish those keys. Another potential concern of keys with long expiry is if you lose all of your private keys, the corresponding public keys will sit on a keyserver (validly) for a long time and cause confusion for people trying to contact you.
Caution: sending your keys to a keyserver is an irrevocable operation - once it’s out there, it’s impossible to take it back, so it’s advisable to try to avoid having a bunch of keys tied to your email address. Of course, that doesn’t stop other people from creating keys with your email address attached to them, and that’s where the web of trust comes in.
The web of trust exists to tie your identity to your keys. The idea is that you go to a keysigning party, full of other security-minded people, and then you all show each other a form of convincing ID (i.e. a government ID, driver’s license, passport etc.) to demonstrate that you are who you claim to be. Then, if they are convinced, they would sign your key (specifically key C). You also do the same for people who’s identities you have verified (you need to break out the private key of C for this).
If lots of keys exist on the internet for your email address, then the web of trust is one way to discern which one actually belongs to you.
Say you attend a keysigning party with Bob, who’s a GPG enthusiast, and he signs your key. Bob has attended another keysigning party where Alice, a debian developer, signed his key. Alice has attended a keysigning party with Linus Torvalds, who signed her key. Most people trust that Linus’s public key really belongs to him, and that he would do his due diligence for any key he’s asked to sign - the same goes for Alice. Bob doesn’t have a big name in the community, but he seems on point with keysigning and insists on a face-to-face meetup before signing anyone’s key (you should too). Because we can trace the signatures to a point of trust beyond reasonable doubt, other people can be credibly certain that your key is tied to your identity.
The truly paranoid will refuse to sign keys until you have known and worked with them for X years, or proven any arbitrary measure of trust‥
To retire your old key, sign a message (with the old key) stating that you’re moving to a new key, ensuring that you include the full fingerprint (or even public key, if you want) of your new key (this is key C), and publish it somewhere.
Then:
Using GPG to encrypt messages doesn’t automatically make you safe, but it’s one component in a toolbox to achieve anonimity online. You have to be careful about leaking information about your identity outside of the encryption. That being said, there real issues with it.
We do have some alternatives: reop looks interesting, but I’ve yet to have a chance to use it.
If one thing’s for certain, GPG isn’t going anywhere fast.
https://casecurity.org/2014/06/10/benefits-of-elliptic-curve-cryptography/↩︎
Not really important for GPG anyway, unless you are encrypting a load of data.↩︎
Or rather, its implementations are.↩︎
Assuming a reasonable key size.↩︎
be very careful about where and how the private key is stored↩︎
This is because the primary key is the link between your identity and your digital keys↩︎