GnuPG¶
Generate new Offline Key¶
This instructions are for generating a master key that can be kept offline. For day-to-day work (signing, encrypting and authenticating) subkeys are generated that can be moved to an online machine or smartcard. The subkeys have a short lifetime allowing to rotate the keys frequently. Because the master key remains the same, your identity won’t change.
Important
Clocks on offline machines tend to drift out of sync and batteries deplete. Do check if the time is correct:
date
Generate Master (Certify) Key
Generate new key with only certify capibility. This key is used later on to certifiy our subkeys with encrypt, sign and authentice capability respectively:
$ gpg --expert --full-generate-key gpg (GnuPG) 2.2.12; Copyright (C) 2018 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) (9) ECC and ECC (10) ECC (sign only) (11) ECC (set your own capabilities) (13) Existing key 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 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? 8 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: Peter Gerber Email address: peter@arbitrary.ch Comment: You selected this USER-ID: "Peter Gerber <peter@arbitrary.ch>" 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: key 4A72372BAF48DADE marked as ultimately trusted gpg: directory '/home/user/.gnupg/openpgp-revocs.d' created gpg: revocation certificate stored as '/home/user/.gnupg/openpgp-revocs.d/E6BFD964AA7CEBD360537DDB4A72372BAF48DADE.rev' public and secret key created and signed. pub brainpoolP512r1 2020-12-31 [C] E6BFD964AA7CEBD360537DDB4A72372BAF48DADE uid Peter Gerber <peter@arbitrary.ch> gpg> quit Save changes? (y/N) y
Replace the ID in the example, E6BFD964AA7CEBD360537DDB4A72372BAF48DADE, with the actual ID in the commands below.
Create Subkeys
Key for encrypting:
$ gpg --expert --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE gpg (GnuPG) 2.2.12; Copyright (C) 2018 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. sec brainpoolP512r1/4A72372BAF48DADE created: 2020-12-31 expires: never usage: C trust: ultimate validity: ultimate [ultimate] (1). Peter Gerber <peter@arbitrary.ch> 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) 400 Key expires at Fri 04 Feb 2022 01:02:42 PM CET 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 brainpoolP512r1/4A72372BAF48DADE created: 2020-12-31 expires: never usage: C trust: ultimate validity: ultimate ssb cv25519/EA5164ADF741144D created: 2020-12-31 expires: 2022-02-04 usage: E [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
Key for signing:
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? 11 Possible actions for a ECDSA/EdDSA key: Sign Authenticate Current allowed actions: Sign (S) Toggle the sign capability (A) Toggle the authenticate capability (Q) Finished Your selection? 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) 400 Key expires at Fri 04 Feb 2022 01:02:56 PM CET 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 brainpoolP512r1/4A72372BAF48DADE created: 2020-12-31 expires: never usage: C trust: ultimate validity: ultimate ssb cv25519/EA5164ADF741144D created: 2020-12-31 expires: 2022-02-04 usage: E ssb ed25519/A9BC0494BD1AE92E created: 2020-12-31 expires: 2022-02-04 usage: S [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
Key for authenticating:
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? 11 Possible actions for a ECDSA/EdDSA key: Sign Authenticate Current allowed actions: Sign (S) Toggle the sign capability (A) Toggle the authenticate capability (Q) Finished Your selection? s Possible actions for a ECDSA/EdDSA key: Sign Authenticate Current allowed actions: (S) Toggle the sign capability (A) Toggle the authenticate capability (Q) Finished Your selection? a Possible actions for a ECDSA/EdDSA key: Sign Authenticate Current allowed actions: Authenticate (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) 400 Key expires at Fri 04 Feb 2022 01:03:14 PM CET 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 brainpoolP512r1/4A72372BAF48DADE created: 2020-12-31 expires: never usage: C trust: ultimate validity: ultimate ssb cv25519/EA5164ADF741144D created: 2020-12-31 expires: 2022-02-04 usage: E ssb ed25519/A9BC0494BD1AE92E created: 2020-12-31 expires: 2022-02-04 usage: S ssb ed25519/01E26E0AAE5D9796 created: 2020-12-31 expires: 2022-02-04 usage: A [ultimate] (1). Peter Gerber <peter@arbitrary.ch> gpg> quit Save changes? (y/N) y
Check and update preferences
The public key has information in it about supported algorithms known as preferences in GnuPG. As new more-secure algorithms are supported and some become insecure, it a good idea to check and if needed update the preferences once in a while.
Get preferences:
$ gpg --batch --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE showpref Secret key is available. sec ed25519/FED9093FB3BCD2D7 created: 2021-01-02 expires: never usage: C trust: ultimate validity: ultimate [ultimate] (1). Test Test <test@example.com> [ultimate] (1). Test Test <test@example.com> Cipher: AES256, AES192, AES, 3DES Digest: SHA512, SHA384, SHA256, SHA224, SHA1 Compression: ZLIB, BZIP2, ZIP, Uncompressed Features: MDC, Keyserver no-modify
List supported algorithms:
$ gpg --version Supported algorithms: Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256 Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224 Compression: Uncompressed, ZIP, ZLIB, BZIP2
Update preferences:
$ gpg --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE Secret key is available. sec ed25519/FED9093FB3BCD2D7 created: 2021-01-02 expires: never usage: C trust: ultimate validity: ultimate [ultimate] (1). Test Test <test@example.com> gpg> setpref AES256 AES192 SHA512 SHA384 Uncompressed ZLIB Set preference list to: Cipher: AES256, AES192, 3DES Digest: SHA512, SHA384, SHA1 Compression: Uncompressed, ZLIB Features: MDC, Keyserver no-modify Really update the preferences? (y/N) y sec ed25519/FED9093FB3BCD2D7 created: 2021-01-02 expires: never usage: C trust: ultimate validity: ultimate [ultimate] (1). Test Test <test@example.com> gpg> q Save changes? (y/N) y
List algorithms in preferred order.
Warning
Preferences are used to decide what algorithms to use when encrypting a message for you.
As a result, it’s crucial that …
… all the OpenPGP implementation you use (on your notebook, mobile, etc.) support these algorithms. You may not be able to decrypt some messages otherwise.
… you make sure to keep less-modern algorithms in the preferences for a while. Keep in mind that people sending you a message must support at least one of the ciphers, digest and compression algorithms in your preferences.
Verify Correctness
Check the keys have the right capabilities:
$ gpg -K E6BFD964AA7CEBD360537DDB4A72372BAF48DADE sec# brainpoolP512r1 2020-12-31 [C] <-- [C]ertify E6BFD964AA7CEBD360537DDB4A72372BAF48DADE uid [ultimate] Peter Gerber <peter@arbitrary.ch> ssb cv25519 2020-12-31 [E] [expires: 2022-02-04] <-- [E]ncrypt ssb ed25519 2020-12-31 [S] [expires: 2022-02-04] <-- [S]ign ssb ed25519 2020-12-31 [A] [expires: 2022-02-04] <-- [A]uthenticate
Export Public Key:
$ gpg -a --export E6BFD964AA7CEBD360537DDB4A72372BAF48DADE >public
Export Secret Subkeys:
$ gpg -a --export-secret-subkeys E6BFD964AA7CEBD360537DDB4A72372BAF48DADE > secret
Only exports the subkey. These keys are intended to be moved to an online machine or smartcard.
Copy Revokation Certificate:
$ cp .gnupg/openpgp-revocs.d/E6BFD964AA7CEBD360537DDB4A72372BAF48DADE.rev revocation
Backup this certificate in case you need to be able revoke the certificate after loosing the master key, the smartcard or the PIN/password to access it.
Export Secret Keys including Master Key:
$ gpg -a --export-secret E6BFD964AA7CEBD360537DDB4A72372BAF48DADE > secret_master
Backup this key but this key should not be moved onto an online machine.
Publish Key via WKD¶
Web Key Directory (WKD) is a simple way to make PGP keys discoverable via a /.well-known/ URL. Current version of GnuPG will attempt to fetch a missing key via WKD automatically should it be missing locally.
See also GnuPG wiki and the specification.
Create policy:
$ mkdir -p ${WEB_SERVER_ROOT}/.well-known/openpgpkey/ $ touch ${WEB_SERVER_ROOT}/.well-known/openpgpkey/policy
An empty policy simply indicates support for WKD.
This needs to be served at https://${DOMAIN}/ where the ${DOMAIN} is the domain of the e-mail address used by the PGP identity.
Create key file
Get the WKD hash (bold) which is later used as filename:
$ gpg --with-wkd-hash -k E6BFD964AA7CEBD360537DDB4A72372BAF48DADE pub brainpoolP512r1 2020-12-31 [C] E6BFD964AA7CEBD360537DDB4A72372BAF48DADE uid [ unknown] Peter Gerber <tor@arbitrary.ch> wbipms79hu4uh1xpsodr369nqi38s8wa@arbitrary.ch uid [ unknown] Peter Gerber <peter@arbitrary.ch> jqbz8wys6j5irhca8bp4qm64b9ii5eyi@arbitrary.ch sub cv25519 2020-12-31 [E] [expires: 2022-02-04] sub ed25519 2020-12-31 [S] [expires: 2022-02-04] sub ed25519 2020-12-31 [A] [expires: 2022-02-04]
For this example, we’ll ignore the second hash for tor@arbitrary.ch.
$ mkdir -p ${WEB_SERVER_ROOT}/.well-known/openpgpkey/hu $ gpg --export E6BFD964AA7CEBD360537DDB4A72372BAF48DADE \ >${WEB_SERVER_ROOT}/.well-known/openpgpkey/hu/jqbz8wys6j5irhca8bp4qm64b9ii5eyi
Configure web server
Set the following headers:
Name
Value
Content-Type
application/octet-stream
Access-Control-Allow-Origin
*
Example Apache2:
<Location /.well-known/openpgpkey/hu/> ForceType application/octet-stream Header always set Access-Control-Allow-Origin "*" </Location>
Example Nginx:
location /.well-known/openpgpkey/hu/ { default_type "application/octet-stream"; add_header Access-Control-Allow-Origin * always; }
Reload the configuration as needed.
Validate the setup
Try fetching the key:
wget -S --spider https://arbitrary.ch/.well-known/openpgpkey/hu/jqbz8wys6j5irhca8bp4qm64b9ii5eyi
Use this online validator.
Keep key in TPM¶
Starting with GnuPG 2.3, it is possible keep keys in a TPM.
See:
Using a TPM with GnuPG 2.3 blog post
Ticket Pass-Through /dev/tpm0 to appVMs for Qubes OS