Keywords: ssh-agent, gpg-agent, pcsc, nitrokey
I recently collected a new Nitrokey Pro. This post explains how I configured it and integrated it into my authentication flow.
Before connecting the Nitrokey
The Nitrokey supports the OpenPGP standard so you’ll be mainly interacting with it using GPG. On Gentoo Linux, you’ll need gnupg with the +smartcard and +usb USE flags enabled.
# echo "app-crypt/gnupg smartcard usb" >> /etc/portage/package.use/gnupg
Next, we’ll install the required packages.
$ sudo emerge -av sys-apps/pcsc-tools sys-apps/pcsc-lite dev-libs/opensc \
app-crypt/ccid app-crypt/gnupg
The abstractions work like the following: gnupg -> pcsc-lite -> opensc -> ccid -> nitrokey.
Connecting the Nitrokey
Here’s the immediate output from dmesg
after connecting the Nitrokey.
[24798.012187] usb 2-2.2: new full-speed USB device number 5 using uhci_hcd
[24798.450042] usb 2-2.2: New USB device found, idVendor=20a0, idProduct=4108,
bcdDevice= 1.01
[24798.450044] usb 2-2.2: New USB device strings: Mfr=1, Product=2,
SerialNumber=3
[24798.450046] usb 2-2.2: Product: Nitrokey Pro
[24798.450047] usb 2-2.2: Manufacturer: Nitrokey
[24798.450048] usb 2-2.2: SerialNumber:
[24798.467777] hid-generic 0003:20A0:4108.0002: hiddev96,hidraw1: USB HID v1.10
Device [Nitrokey Nitrokey Pro] on usb-0000:02:00.0-2.2/input0
Let’s see if pcsc supports the smart card.
$ sudo pcscd -a -d -f
[..snip..]
00005549 /var/tmp/portage/sys-apps/pcsc-lite-1.8.24/work/pcsc-lite-1.8.24/src/eventhandler.c:289:EHStatusHandlerThread()
powerState: POWER_STATE_POWERED
[..snip..]
This looks good; the card was recognised. Next, we’ll start the service and let it run on boot.
$ sudo systemctl start pcscd.service pcscd.socket
$ sudo systemctl enable pcscd.service pcscd.socket
The services should now be loaded in systemctl memory and running.
$ systemctl list-units --type=service,socket --state=running pcsc*
UNIT LOAD ACTIVE SUB DESCRIPTION
pcscd.service loaded active running PC/SC Smart Card Daemon
pcscd.socket loaded active running PC/SC Smart Card Daemon Activation Socket
Finally, we’ll confirm that gpg can see the card as well.
$ gpg --card-status
Reader ...........: Nitrokey Nitrokey Pro () 00 00
Application ID ...:
Version ..........: 3.3
Manufacturer .....: ZeitControl
Serial number ....:
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
And gpg looks good too.
Keypair configuration
According to the Nitrokey datasheet it supports RSA-2048 up to RSA-4096 and ECC-256 up to ECC-512 (Brainpool and NIST algorithms). For compatibility reasons, it’s probably best to use RSA-2048 keypairs despite them being slower and larger than equivalent ECC keypairs. In this tutorial I show RSA-2048. For my personal key, I’ll use ECC which is not shown in this tutorial.
- According to Microsoft Research, ECC (elliptical curve cryptography) keypairs are easier to crack than RSA keypairs with a sufficiently powerful quantum computer.
- The algorithms supported by the Nitrokey are supposedly vunerable to side-channel attacks due to not implementing a Montogomery power ladder.
- ECC is used for Bitcoin, just secp256k1 which is not supported by the Nitrokey.
- The kernel.org guidelines say nistp256 is suitable.
We’ll be creating:
- All keys: RSA-2048, expiring yearly on 1 August, SHA-2 series output digest
- Primary key: certify and signing ** Subkey 1: (encryption) ** Subkey (authentication)
- Revocation certificate stored offsite
$ gpg --full-generate-key --expert
gpg (GnuPG) 2.2.15; 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
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want for the subkey? (2048)
Requested keysize is 2048 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) 358
Key expires at Sat 01 Aug 2020 20:33:09 BST
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Antony Jepson
Email address: a@plkt.io/
Comment: RSA key for Antony Jepson. Renewed every 1 August.
You selected this USER-ID:
"Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/>"
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.
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: /home/bnt/.gnupg/trustdb.gpg: trustdb created
gpg: key 718044D8003D317A marked as ultimately trusted
gpg: directory '/home/bnt/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/bnt/.gnupg/openpgp-revocs.d/0F8D4AD674DB570DB095CB3F718044D8003D317A.rev'
public and secret key created and signed.
pub rsa2048 2019-08-09 [SC] [expires: 2020-08-01]
0F8D4AD674DB570DB095CB3F718044D8003D317A
uid Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/>
sub rsa2048 2019-08-09 [E] [expires: 2020-08-01]
$ gpg --edit-key --expert a@plkt.io/
gpg (GnuPG) 2.2.15; 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
gpg: next trustdb check due at 2020-08-01
sec rsa2048/718044D8003D317A
created: 2019-08-09 expires: 2020-08-01 usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/692971AD1D29742D
created: 2019-08-09 expires: 2020-08-01 usage: E
[ultimate]
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> 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? 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? A Possible actions for a RSA key: Sign Encrypt Authenticate Current allowed actions: Sign Encrypt Authenticate (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 Authenticate (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: 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? (2048) Requested keysize is 2048 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) 358 Key expires at Sat 01 Aug 2020 20:37:48 BST 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 rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
[ultimate]
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> quit Save changes? (y/N) y
Now, back up your key and save it somewhere safe. We do this now because once they keys are copied to your Nitrokey they are deleted.
$ gpg --export-secret-keys a@plkt.io/ > sec-key.asc
Next, we’ll copy the keys to the Nitrokey. First the signature key, then the encryption key, then the authentication key (for SSH).
$ gpg --edit-key --expert a@plkt.io/
gpg (GnuPG) 2.2.15; 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.
sec rsa2048/718044D8003D317A
created: 2019-08-09 expires: 2020-08-01 usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/692971AD1D29742D
created: 2019-08-09 expires: 2020-08-01 usage: E
ssb rsa2048/73CCBEF81E3522EB
created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> keytocard Really move the primary key? (y/N) y Please select where to store the key: (1) Signature key (3) Authentication key Your selection? 1 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> key 1 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb* rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> keytocard Please select where to store the key: (2) Encryption key Your selection? 2 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb* rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> key 2 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb* rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb* rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> key 1 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb* rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> keytocard Please select where to store the key: (3) Authentication key Your selection? 3 sec rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01 usage: SC trust: ultimate validity: ultimate ssb rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01 usage: E ssb* rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01 usage: A
(1). Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/> gpg> quit Save changes? (y/N) y
The public key can be exported and stored in any easily retrievable place.
$ gpg --armor --export a@plkt.io/ > pubkey.asc
Here’s the final state of the Nitrokey.
$ gpg --card-edit
Reader ...........: Nitrokey Nitrokey Pro () 00 00
Application ID ...:
Version ..........: 3.3
Manufacturer .....: ZeitControl
Serial number ....:
Name of cardholder: [not set]
Language prefs ...: de
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 64 64 64
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
Signature key ....: 0F8D 4AD6 74DB 570D B095 CB3F 7180 44D8 003D 317A
created ....: 2019-08-09 19:34:03
Encryption key....: FECA 217D E1E5 96AA A7F5 86F1 6929 71AD 1D29 742D
created ....: 2019-08-09 19:34:03
Authentication key: D6CF ED7E FA74 999D 2E99 AEE4 73CC BEF8 1E35 22EB
created ....: 2019-08-09 19:36:50
General key info..:
pub rsa2048/718044D8003D317A 2019-08-09 Antony Jepson (RSA key for Antony Jepson. Renewed every 1 August.) <a@plkt.io/>
sec> rsa2048/718044D8003D317A created: 2019-08-09 expires: 2020-08-01
card-no:
ssb> rsa2048/692971AD1D29742D created: 2019-08-09 expires: 2020-08-01
card-no:
ssb> rsa2048/73CCBEF81E3522EB created: 2019-08-09 expires: 2020-08-01
card-no:
gpg/card> quit
More information available on Nitrokey’s website (guide)[https://www.nitrokey.com/documentation/openpgp-create-backup].
The keys shown in this example are just for reference. My actual public key is stored at https://plkt.io/key.
Using the keypair
So I think for most people this is the stopping point — people don’t actually integrate it into their flow. Here’s the references I used for integrating it into my daily flow.
Signing code commits
GitHub has a great guide.
In the local repository, issue git config commit.gpgsign true
. Then when you commit, add the S flag: git commit -S -m commit message
.
Encrypting and signing email
I use a mixture of Outlook and Mutt for email. I use Outlook for day-to-day email and Mutt for mailing lists and important emails. See the Mutt documentation for help.
Logging into remote systems
Two helpful guides: Arch Wiki and the top Google result Using gpg-agent effectively.
Encrypting files
Use the official GPG documentation.
Summary
Using public keys with a smart card wasn’t as difficult as expected. I think you need to incrementally introduce it into your habits over time. Start by occasionally sending encrypted email — see how people respond. Attach the digest to the email instead of including it inline.
Let me know if you found any issues with the instructions above.