Backup your GPG keys
After creating your GPG keys from your air-gapped system, you might want to back them up to prevent the loss of data or the loss of access to your servers. To ensure that your private keys are not leaked, you should perform the backup operations from the air-gapped system.
Files to backup
It is advised to backup the following files :
- gpg.conf
- pubring.kbx
- the private key
- the revocation certificate
Public files
The following files are public and can be stored on a piece of paper, or a basic USB key:
- gpg.conf
- pubring.kbx
Export your public key with :
gpg2 --export --armor $KEYID > pubkey.asc
pubkey.asc
is legible ASCII and will be later used to import your public GPG
key.
And create the public gpg ring with:
gpg2 --export $KEYID > pubring.gpg
Private files
The following files should be stored in a very secure place. Giving access to these files to someone means compromising your key :
- the private key
- the revocation certificate
- your private sub keys
To store these files securely we will back them up :
- on an encrypted USB key
- on paper
- as a QR code, on paper
Backup on an encrypted USB
Source: drduh.
To backup the keys on an encrypted USB drive we will use LUKS
along with a
basic USB drive.
You can also use a Nitrokey which is fully
open-source, or an IronKey
which is not open-source.
Plug your USB
To create an encrypted USB drive, first attach it and check its label:
$ dmesg | tail
[ 7667.607011] scsi8 : usb-storage 2-1:1.0
[ 7667.608766] usbcore: registered new interface driver usb-storage
[ 7668.874016] scsi 8:0:0:0: USB 0: 0 ANSI: 6
[ 7668.874242] sd 8:0:0:0: Attached scsi generic sg4 type 0
[ 7668.874682] sd 8:0:0:0: [sde] 62980096 512-byte logical blocks: (32.2 GB/30.0 GiB)
[ 7668.875022] sd 8:0:0:0: [sde] Write Protect is off
[ 7668.875023] sd 8:0:0:0: [sde] Mode Sense: 43 00 00 00
[ 7668.877939] sde: sde1
[ 7668.879514] sd 8:0:0:0: [sde] Attached SCSI removable disk
Check the size to make sure it’s the right drive:
$ sudo fdisk -l | grep /dev/sde
Disk /dev/sde: 30 GiB, 32245809152 bytes, 62980096 sectors
/dev/sde1 2048 62980095 62978048 30G 6 FAT16
Create a new partition table
Erase and create a new partition table:
$ sudo fdisk /dev/sde
Welcome to fdisk (util-linux 2.25.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): o
Created a new DOS disklabel with disk identifier 0xeac7ee35.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Remove and reinsert the USB drive, then create a new partition, selecting defaults::
$ sudo fdisk /dev/sde
Welcome to fdisk (util-linux 2.25.2).
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): 1
First sector (2048-62980095, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-62980095, default 62980095):
Created a new partition 1 of type 'Linux' and of size 30 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Encrypt the partition
Use LUKS to encrypt the new partition:
$ sudo cryptsetup luksFormat /dev/sde1
WARNING!
========
This will overwrite data on /dev/sde1 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Mount the partition
Mount the partition:
$ sudo cryptsetup luksOpen /dev/sde1 encrypted-usb
Enter passphrase for /dev/sde1:
Create a filesystem:
$ sudo mkfs.ext4 /dev/mapper/encrypted-usb -L encrypted-usb
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 7871744 4k blocks and 1970416 inodes
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
Mount the filesystem:
$ sudo mkdir /mnt/usb
$ sudo mount /dev/mapper/encrypted-usb /mnt/usb
Transfer your files
Finally, copy files to it:
$ sudo cp -avi $GNUPGHOME /mnt/usb
‘/tmp/tmp.aaiTTovYgo’ -> ‘/mnt/usb/tmp.aaiTTovYgo’
‘/tmp/tmp.aaiTTovYgo/revoke.txt’ -> ‘/mnt/usb/tmp.aaiTTovYgo/revoke.txt’
‘/tmp/tmp.aaiTTovYgo/gpg.conf’ -> ‘/mnt/usb/tmp.aaiTTovYgo/gpg.conf’
‘/tmp/tmp.aaiTTovYgo/trustdb.gpg’ -> ‘/mnt/usb/tmp.aaiTTovYgo/trustdb.gpg’
‘/tmp/tmp.aaiTTovYgo/random_seed’ -> ‘/mnt/usb/tmp.aaiTTovYgo/random_seed’
‘/tmp/tmp.aaiTTovYgo/master.key’ -> ‘/mnt/usb/tmp.aaiTTovYgo/master.key’
‘/tmp/tmp.aaiTTovYgo/secring.gpg’ -> ‘/mnt/usb/tmp.aaiTTovYgo/secring.gpg’
‘/tmp/tmp.aaiTTovYgo/mastersub.key’ -> ‘/mnt/usb/tmp.aaiTTovYgo/mastersub.key’
‘/tmp/tmp.aaiTTovYgo/sub.key’ -> ‘/mnt/usb/tmp.aaiTTovYgo/sub.key’
‘/tmp/tmp.aaiTTovYgo/pubring.gpg~’ -> ‘/mnt/usb/tmp.aaiTTovYgo/pubring.gpg~’
‘/tmp/tmp.aaiTTovYgo/pubring.gpg’ -> ‘/mnt/usb/tmp.aaiTTovYgo/pubring.gpg’
Make sure the correct files were copied, then unmount and disconnected the encrypted USB drive:
$ sudo umount /mnt/usb
$ sudo cryptsetup luksClose encrypted-usb
Backup with paperkey
In this example we backup the master key and its subkeys with paperkey.
List existing secret keys
First we can list the existing secret keys. Note in this example there is only the master key, but if you have already created subkeys, they will be backed up as well.
$ gpg2 --list-secret-keys
# Output
gpg: WARNING: unsafe permissions on homedir '/tmp/keyCreation'
/tmp/keyCreation/pubring.kbx
----------------------------
sec rsa4096/0x45B2745200A5D6B1 2017-10-03 [SC] [expires: 2020-10-02]
Key fingerprint = 0B91 39BF 0D9F 3C96 F505 9B30 45B2 7452 00A5 D6B1
uid [ultimate] John Doe <johndoe@mail.com>
Backup the master key
We create a directory that will hold the
mkdir backup
And we backup the master key and subkeys with paperkey
gpg2 --export-secret-keys johndoe@mail.com | paperkey > backup/private.keys.paperkey
About gpg2 --export-secret-subkeys johndoe@mail.com
:
The second form of the command has the special property to render the secret part of the primary key useless; this is a GNU extension to OpenPGP and other implementations can not be expected to successfully import such a key. Its intended use is in generating a full key with an additional signing subkey on a dedicated machine. This command then exports the key without the primary key to the main machine.
The name of the backup file starts with the key signature. Note that the exported key is still encrypted with your password, so make sure that you remember it later !
Print and store
Now that you have the key exported as ASCII text, you can print it and store it in a secure place (a safe in your bank for instance). If you ever need to manage your subkeys, you will have to restore your master key on an air-gapped system.
Be careful with the printer you use, they often store in memory the files they were transmitted. Even if your file is encrypted, it is still a risk to acknowledge.
If you are afraid to forget your password, write it on the paper backup before storing it in your very secure place !
Backup as QR code
You should also have a QR code backup of your private keys. The advantages are :
- it adds a redundancy : if your ASCII backup is damaged, you will have your QR code backup available.
- it prevents human error : typing your master key by hand from your ASCII backup will be tedious. Using a QR code facilitates its retrieval.
- it is damage resistant : QR codes have error correction capability to restore data if the code is damaged.
Export the keys
gpg2 --export-secret-keys --armor johndoe@mail.com > private.master.key.asc
The exported key is encrypted but readable in the ASCII format. This export does not contains correction checksums and is less readable than the paperkey export; however this lack of redundancy is exactly what we look for since the QR code will manage the redundancy itself.
The export should look like that :
Split the key
qrencode
has a limit of 2953 characters :
qrencode is encoding your private GPG key as 8 bit (binary|utf-8), because the key is not pure alphanumeric. It contains special character. the alphanumeric mode only supports those special character .(%*+-./:). So the maximum GPG key can only be 2953 char long.
To circumvent this limit we will split the exported private key and generate multiple QR codes.
split -C 2500 private.keys.asc splitkey-
This creates two files :
- splitkey-aa
- splitkey-ab
Create the QR codes
We create the two QR codes with qrencode
:
cat splitkey-aa | qrencode -o private.keys.qrcode.1.png
cat splitkey-ab | qrencode -o private.keys.qrcode.2.png
Here is a command to do it automatically :
i=0; for f in $(ls splitkey*); do echo "Encoding $f : file $i" \
&& cat $f | qrencode -o private.keys.qrcode.$i.png; i=$(($i+1)); done
Verify the QR codes
We can verify that the QR codes we created correctly by extracting the data
from the QR codes with zbarimg
:
zbarimg private.keys.qrcode.2.png
Test your backups
Before storing your backups in a secure place you should always try to restore them. There is an article explaining how to restore your backups, so before doing anything else, test the restoration of your backup. A backup that you can’t restore is just garbage securely stored.
Backup other files
Don’t forget to backup the revocation in a secure place (in ASCII and QR code),
you can find it in openpgp-revocs.d
. If you haven’t done so, you will also
need to backup your private keys.
And don’t forget to backup the following public files :
- gpg.conf
- pubring.kbx
Sources: