Post

Move PGP Keys to Security Key Hardware

Move PGP Keys to Security Key Hardware

This guide presumes you have completed the following steps:

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
This post is licensed under CC BY 4.0 by the author.