542 lines
16 KiB
Markdown
542 lines
16 KiB
Markdown
# OpenPGP Setup
|
|
|
|
## Master key
|
|
|
|
```console
|
|
$ gpg --gen-random --armor 0 24
|
|
wgwCNncu2POgMJwX/zSJUrBpRvgD95LT
|
|
```
|
|
|
|
**Important:** Save this credential in a permanent, secure place as it will be needed to issue new sub-keys after expiration, and to provision additional YubiKeys.
|
|
|
|
Generate a new key with GPG, selecting `(8) RSA (set your own capabilities)`, Certify capability only and `4096` bit key size.
|
|
|
|
**Important:** Do not set the master key to expire.
|
|
|
|
```console
|
|
$ gpg --expert --full-generate-key
|
|
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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
|
|
(14) Existing key from card
|
|
Your selection? 8
|
|
|
|
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? e
|
|
|
|
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
|
|
Current allowed actions: Sign Certify
|
|
|
|
(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
|
|
|
|
(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? (3072) 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)
|
|
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: Maurice Preuß
|
|
Email address: hello@envoyr.com
|
|
Comment: Testing
|
|
You are using the 'utf-8' character set.
|
|
You selected this USER-ID:
|
|
"Maurice Preuß (Testing) <hello@envoyr.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: /root/.gnupg/trustdb.gpg: trustdb created
|
|
gpg: key 2FB2BECD1F7F3DD2 marked as ultimately trusted
|
|
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
|
|
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/8941D3AA5A48FDA1C9B9655D2FB2BECD1F7F3DD2.rev'
|
|
public and secret key created and signed.
|
|
|
|
pub rsa4096 2022-04-24 [C]
|
|
8941D3AA5A48FDA1C9B9655D2FB2BECD1F7F3DD2
|
|
uid Maurice Preuß (Testing) <hello@envoyr.com>
|
|
```
|
|
|
|
Export the key ID as a variable (`KEYID`) for use later:
|
|
|
|
```console
|
|
$ export KEYID=8941D3AA5A48FDA1C9B9655D2FB2BECD1F7F3DD2
|
|
```
|
|
|
|
## Sign with existing key
|
|
|
|
**Optional**: If you already have a PGP key, you may want to sign the new key with the old one to prove that the new key is controlled by you.
|
|
|
|
Export your existing key to move it to the working keyring:
|
|
|
|
```console
|
|
$ gpg --export-secret-keys --armor --output /tmp/new.sec
|
|
```
|
|
|
|
Then sign the new key:
|
|
|
|
```console
|
|
$ gpg --default-key $OLDKEY --sign-key $KEYID
|
|
```
|
|
|
|
## Sub keys
|
|
|
|
Edit the master key to add sub-keys:
|
|
|
|
```console
|
|
$ gpg --expert --edit-key $KEYID
|
|
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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 rsa4096/2FB2BECD1F7F3DD2
|
|
created: 2022-04-24 expires: never usage: C
|
|
trust: ultimate validity: ultimate
|
|
[ultimate] (1). Maurice Preuß (Testing) <hello@envoyr.com>
|
|
```
|
|
|
|
Use `4096`-bit RSA keys.
|
|
|
|
Use a `1 year` expiration for sub-keys - they can be renewed using the offline master key. See rotating keys.
|
|
|
|
### Signing
|
|
|
|
Create a signing key by selecting `addkey` then `(4) RSA (sign only)`:
|
|
|
|
```console
|
|
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
|
|
(14) Existing key from card
|
|
Your selection? 4
|
|
RSA keys may be between 1024 and 4096 bits long.
|
|
What keysize do you want? (3072) 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 Mon 24 Apr 2023 04:42:12 PM UTC
|
|
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/2FB2BECD1F7F3DD2
|
|
created: 2022-04-24 expires: never usage: C
|
|
trust: ultimate validity: ultimate
|
|
ssb rsa4096/AFE0490C5483E698
|
|
created: 2022-04-24 expires: 2023-04-24 usage: S
|
|
[ultimate] (1). Maurice Preuß (Testing) <hello@envoyr.com>
|
|
```
|
|
|
|
### Encryption
|
|
|
|
Next, create an encryption key by selecting `(6) RSA (encrypt only)`:
|
|
|
|
```console
|
|
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
|
|
(14) Existing key from card
|
|
Your selection? 6
|
|
RSA keys may be between 1024 and 4096 bits long.
|
|
What keysize do you want? (3072) 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 Mon 24 Apr 2023 04:43:19 PM UTC
|
|
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/2FB2BECD1F7F3DD2
|
|
created: 2022-04-24 expires: never usage: C
|
|
trust: ultimate validity: ultimate
|
|
ssb rsa4096/AFE0490C5483E698
|
|
created: 2022-04-24 expires: 2023-04-24 usage: S
|
|
ssb rsa4096/E6CF1F243E533507
|
|
created: 2022-04-24 expires: 2023-04-24 usage: E
|
|
[ultimate] (1). Maurice Preuß (Testing) <hello@envoyr.com>
|
|
```
|
|
|
|
### Authentication
|
|
|
|
Finally, create an authentication key.
|
|
|
|
GPG doesn't provide an authenticate-only key type, so select `(8) RSA (set your own capabilities)` and toggle the required capabilities until the only allowed action is Authenticate:
|
|
|
|
```console
|
|
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
|
|
(14) Existing key from card
|
|
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? (3072) 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 Mon 24 Apr 2023 04:44:50 PM UTC
|
|
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/2FB2BECD1F7F3DD2
|
|
created: 2022-04-24 expires: never usage: C
|
|
trust: ultimate validity: ultimate
|
|
ssb rsa4096/AFE0490C5483E698
|
|
created: 2022-04-24 expires: 2023-04-24 usage: S
|
|
ssb rsa4096/E6CF1F243E533507
|
|
created: 2022-04-24 expires: 2023-04-24 usage: E
|
|
ssb rsa4096/2209B814758777B0
|
|
created: 2022-04-24 expires: 2023-04-24 usage: A
|
|
[ultimate] (1). Maurice Preuß (Testing) <hello@envoyr.com>
|
|
```
|
|
|
|
Finish by saving the keys.
|
|
|
|
```console
|
|
gpg> save
|
|
```
|
|
|
|
## Verify
|
|
|
|
List the generated secret keys and verify the output:
|
|
|
|
```console
|
|
$ gpg -K
|
|
/root/.gnupg/pubring.kbx
|
|
------------------------
|
|
sec rsa4096 2022-04-24 [C]
|
|
8941D3AA5A48FDA1C9B9655D2FB2BECD1F7F3DD2
|
|
uid [ultimate] Maurice Preuß (Testing) <hello@envoyr.com>
|
|
ssb rsa4096 2022-04-24 [S] [expires: 2023-04-24]
|
|
ssb rsa4096 2022-04-24 [E] [expires: 2023-04-24]
|
|
ssb rsa4096 2022-04-24 [A] [expires: 2023-04-24]
|
|
```
|
|
|
|
## Export keys and ownertrust
|
|
|
|
The master key and sub-keys will be encrypted with your passphrase when exported.
|
|
|
|
Save a copy of your keys:
|
|
|
|
```console
|
|
$ gpg --armor --export $KEYID > public.key
|
|
$ gpg --armor --export-secret-keys $KEYID > master.asc
|
|
$ gpg --armor --export-secret-subkeys $KEYID > subkeys.asc
|
|
$ gpg --export-ownertrust > ownertrust.txt
|
|
```
|
|
|
|
## Import keys and ownertrust
|
|
|
|
```console
|
|
$ gpg --import public.key
|
|
$ gpg --import master.asc
|
|
$ gpg --import subkeys.asc
|
|
$ gpg --import-ownertrust ownertrust.txt
|
|
```
|
|
|
|
## Ultimately trust the imported key
|
|
|
|
This is so that I can encrypt data using my public key
|
|
|
|
```console
|
|
$ gpg --edit-key 1E0B5331219BEA88
|
|
gpg> trust
|
|
Your decision? 5 (Ultimate trust)
|
|
```
|
|
|
|
**Information:** If I don't trust the public key then I see the following message when trying to encrypt something with it:
|
|
|
|
```console
|
|
gpg: <key-id>: There is no assurance this key belongs to the named user
|
|
```
|
|
|
|
## Revocation certificate
|
|
|
|
Although we will backup and store the master key in a safe place, it is best practice to never rule out the possibility of losing it or having the backup fail. Without the master key, it will be impossible to renew or rotate subkeys or generate a revocation certificate, the PGP identity will be useless.
|
|
|
|
Even worse, we cannot advertise this fact in any way to those that are using our keys. It is reasonable to assume this will occur at some point and the only remaining way to deprecate orphaned keys is a revocation certificate.
|
|
|
|
To create the revocation certificate:
|
|
|
|
```console
|
|
$ gpg --output revoke.asc --gen-revoke $KEYID
|
|
|
|
sec rsa4096/2FB2BECD1F7F3DD2 2022-04-24 Maurice Preuß (Testing) <hello@envoyr.com>
|
|
|
|
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? 1
|
|
Enter an optional description; end it with an empty line:
|
|
>
|
|
Reason for revocation: Key has been compromised
|
|
(No description given)
|
|
Is this okay? (y/N) y
|
|
ASCII armored output forced.
|
|
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!
|
|
```
|
|
|
|
The `revoke.asc` certificate file should be stored (or printed) in a (secondary) place that allows retrieval in case the main backup fails.
|
|
|
|
## Create new USB
|
|
|
|
Write it with random data to prepare for encryption (1x random & 1x null):
|
|
|
|
```console
|
|
$ sudo shred -vfzn1 /dev/sdc
|
|
```
|
|
|
|
Erase and create a new partition table:
|
|
|
|
```console
|
|
$ sudo fdisk /dev/sdc
|
|
|
|
Welcome to fdisk (util-linux 2.33.1).
|
|
Changes will remain in memory only, until you decide to write them.
|
|
Be careful before using the write command.
|
|
|
|
Device does not contain a recognized partition table.
|
|
Created a new DOS disklabel with disk identifier 0x3c1ad14a.
|
|
|
|
Command (m for help): g
|
|
Created a new GPT disklabel (GUID: 4E7495FD-85A3-3E48-97FC-2DD8D41516C3).
|
|
|
|
Command (m for help): w
|
|
The partition table has been altered.
|
|
Calling ioctl() to re-read partition table.
|
|
Syncing disks.
|
|
```
|
|
|
|
Create a new partition with a 25 Megabyte size:
|
|
|
|
```console
|
|
$ sudo fdisk /dev/sdc
|
|
|
|
Welcome to fdisk (util-linux 2.33.1).
|
|
Changes will remain in memory only, until you decide to write them.
|
|
Be careful before using the write command.
|
|
|
|
Command (m for help): n
|
|
Partition type
|
|
p primary (0 primary, 0 extended, 4 free)
|
|
e extended (container for logical partitions)
|
|
Select (default p): p
|
|
Partition number (1-4, default 1):
|
|
First sector (2048-31116287, default 2048):
|
|
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-31116287, default 31116287): +25M
|
|
|
|
Created a new partition 1 of type 'Linux' and of size 25 MiB.
|
|
|
|
Command (m for help): w
|
|
The partition table has been altered.
|
|
Calling ioctl() to re-read partition table.
|
|
Syncing disks.
|
|
```
|
|
|
|
Use LUKS to encrypt the new partition:
|
|
|
|
```console
|
|
$ sudo cryptsetup luksFormat /dev/sdcp1
|
|
|
|
WARNING!
|
|
========
|
|
This will overwrite data on /dev/sdcp1 irrevocably.
|
|
|
|
Are you sure? (Type uppercase yes): YES
|
|
Enter passphrase for /dev/sdcp1:
|
|
Verify passphrase:
|
|
```
|
|
|
|
Mount the partition:
|
|
|
|
```console
|
|
$ sudo cryptsetup luksOpen /dev/sdcp1 secret
|
|
Enter passphrase for /dev/sdcp1:
|
|
```
|
|
|
|
Create a filesystem:
|
|
|
|
```console
|
|
$ sudo mkfs.ext2 /dev/mapper/secret -L gpg
|
|
Creating filesystem with 9216 1k blocks and 2304 inodes
|
|
Superblock backups stored on blocks:
|
|
8193
|
|
|
|
Allocating group tables: done
|
|
Writing inode tables: done
|
|
Writing superblocks and filesystem accounting information: done
|
|
```
|
|
|
|
Mount the filesystem and copy the temporary directory with the keyring:
|
|
|
|
```console
|
|
$ sudo mkdir /mnt/encrypted-storage
|
|
|
|
$ sudo mount /dev/mapper/secret /mnt/encrypted-storage
|
|
|
|
$ sudo cp -avi $GNUPGHOME /mnt/encrypted-storage/
|
|
```
|
|
|
|
Unmount, close and disconnect the encrypted volume:
|
|
|
|
```console
|
|
$ sudo umount /mnt/encrypted-storage/
|
|
|
|
$ sudo cryptsetup luksClose secret
|
|
```
|
|
|
|
## Transfer keys
|
|
|
|
see https://github.com/envoyr/yubikey-guide#transfer-keys
|