Move PGP Keys to Security Key Hardware
This guide presumes you have completed the following steps:
- Generated your PGP Certify key.
- Uploaded your public keys to keyservers such as https://keys.openpgp.org.
- Noted the full 40-character fingerprint. Example: E108123456FB2280ABC123DAE24318EF3BABCDEF
- Secured PGP key backups using paperkey or offline storage
Selection of security key hardware
Whatever security key (historically called smart card) device you choose, ensure it is compatible with GnuPG. My preference is the YubiKey 5 NFC. It’s a USB device with NFC capability, allowing use on both laptops and mobile phones.
Starting from firmware version 5.7.x, this device supports both RSA 4096 and ED25519 (GnuPG’s default) cryptographic standards. It also includes U2F for securing your online accounts. If you’re in India, you can purchase the device from Etherbit.
Installing the supporting software
Ensure the smart card daemon is installed if it’s not already present.
1
sudo apt install scdaemon
After plugging in the security key, it should work well with GnuPG. You can view the complete card details using the following command.
1
gpg --card-status
The output looks like the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Reader ...........: XXXX:XXXX:X:X
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: XXXXXXXX
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
Execute the following commands while the device is connected to the USB socket.
Update Default User and Admin PINs
Execute the command below to switch to interactive mode:
1
gpg --card-edit
Alter the device’s user PIN and admin PIN from their default settings. The initial user PIN is 123456, and the default admin PIN is 12345678. Note that PINs can include non-numeric characters. To update the PINs, enter admin followed by passwd.
1
2
3
4
5
6
7
8
9
10
11
12
13
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX detected
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection?
Modify the user PIN (option 1) and the admin PIN (option 3). The changes are saved automatically to the device. Exit the interactive GnuPG prompt by typing Q.
Transferring PGP Keys to Secure Key Hardware
To transfer subkeys to the hardware device, execute the following command:
1
gpg --edit-key [fingerprint]
Choose a key by typing key 1. The selection is indicated by ssb*
instead of just ssb
. Use keytocard
to transfer the subkey to the device. Toggle the selection by typing key 1 again. Repeat this process for the remaining subkeys, which are (E)ncryption, (S)igning, and (A)uthentication.
1
gpg > key 1 # Typing key 1 two times will toggle the selection
1
gpg > keytocard
It will prompt you for the GPG password you set when creating the Certify key, as well as the device admin password.
Execute the following command to verify if the keys have been relocated.
1
gpg --list-secret-keys
The output appears as follows:
1
2
3
4
5
6
7
8
/home/nayab/.gnupg/pubring.kbx
------------------------------
sec rsa4096 2024-11-16 [C] [expires: 2027-11-16]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid [ultimate] Nayab Sayed <xxxxxxxx@gmail.com>
ssb> cv25519 2024-11-16 [E]
ssb> ed25519 2024-11-16 [S]
ssb> ed25519 2024-11-16 [A]
From the above command output, the strings change to sub>
instead of sub
. Additionally, all your private keys will display a string called shadowed-private-key, indicating the subkeys are moved to a hardware security key.
1
strings ~/.gnupg/private-keys-v1.d/*.key | grep shadowed-private-key
If you now check the card status, you will also see the subkeys information.
1
gpg --card-status
Here’s an example of the output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Reader ...........: XXXX:XXXX:X:X
Application ID ...: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: XXXXXXXX
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 1
KDF setting ......: off
Signature key ....: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
created ....: 2024-11-16 16:15:39
Encryption key....: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
created ....: 2024-11-16 16:14:44
Authentication key: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
created ....: 2024-11-16 16:15:58
General key info..: sub ed25519/XXXXXXXXXXXXXXXX 2024-11-16 <primary id>
sec rsa4096/XXXXXXXXXXXXXXXX created: 2024-11-16 expires: 2027-11-16
ssb> cv25519/XXXXXXXXXXXXXXXX created: 2024-11-16 expires: never
card-no: XXXX XXXXXXXX
ssb> ed25519/XXXXXXXXXXXXXXXX created: 2024-11-16 expires: never
card-no: XXXX XXXXXXXX
ssb> ed25519/XXXXXXXXXXXXXXXX created: 2024-11-16 expires: never
card-no: XXXX XXXXXXXX
Verify the device functioning
Enter the following commands. If successful, you will see Good signature in the output.
1
2
echo "Hello world" | gpg --clearsign > /tmp/test.asc
gpg --verify /tmp/test.asc