Starting with GPG and YubiKey09 Mar 2019 #GPG
What is public-key cryptography?
There are many guides available online which describe the basics of public-key cryptography. This post will not focus on the basics but rather a specific implementation of using GPG with a YubiKey. With this approach you’ll have your GPG secrets in a portable and secure device which you can then use on any machine.
In short, public-key cryptography is aimed at allowing two parties to securely generate a secret, a secure key, through an insecure communication channel. In essence, two parties will share some public information, completely in the clear for anyone to see/record, yet they will still arrive at the same secret key! With this secret key, both parties can then encrypt data and securely pass it between themselves.
One key assumption with public-key cryptography is that the private portions of this key actually remains secret. Due to this, the Yubikey provides an excellent solution. The Yubikey hardware token provides a secure hardware solution to store OpenPGP keys, and act as a second factor device for many web services. With the Yubikey, and GPG, you can securely use your private GPG keys with the knowledge that it is techinically infeasible to remove them from the device.
In order to follow this you’ll want the following:
- A YubiKey 4 or better which supports 4096 bit RSA keys. Ideally buy two of them to have a backup.
- Two USB drives to create a secure OS (Tails) and backup your GPG keys. This is important because without the backup you will have no way to recover your GPG secret if you lose or damge your Yubikeys.
- Some time and patience. You’ll probably run into problems and will have to debug.
This will basically follow the guide by drduh with some additional details where I ran into issues.
Creating your GPG keys securely
One of the main benefits of using a Yubikey is that you can be certain that your private keys are actually secure. If you generate all of these “secret” keys on a public or compromised system then none of this stuff really matters. For this reason, it makes the most sense to do the following on a secure system, such as Tails OS.
Follow the instructions and create a secure Tails OS. You’ll essentially download Tails, create a live USB, then boot to this version and create a really secure version of Tails on your second USB drive. It’s important that the system you use to create your GPG keys is actually secure or it’ll defeat the whole point of your Yubikey if someone can just read your private key directly. If you’re really paranoid you could even use Tails on an airgapped machine.
Once you have Tails setup, boot into it and install the following software
sudo apt-get update sudo apt-get install -y \ curl gnupg2 gnupg-agent \ cryptsetup scdaemon pcscd \ yubikey-personalization \ dirmngr \ secure-delete \ hopenpgp-tools
Creating new GPG keys
Here we’ll create brand new keys. If you want you could transfer already created keys onto your Tails distribution. However, by securely creating brand new keys on Tails you can be more sure that the only copy of your private key will exist securely on your Yubikey and your backup.
First we’ll create a temporary directory for GPG
export GNUPGHOME=$(mktemp -d); echo $GNUPGHOME
Now you can use the hardended GPG settings from here or copy the following in
personal-cipher-preferences AES256 AES192 AES personal-digest-preferences SHA512 SHA384 SHA256 personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed cert-digest-algo SHA512 s2k-digest-algo SHA512 s2k-cipher-algo AES256 charset utf-8 fixed-list-mode no-comments no-emit-version keyid-format 0xlong list-options show-uid-validity verify-options show-uid-validity with-fingerprint require-cross-certification no-symkey-cache throw-keyids use-agent
We’ll start by creating a Master Key. This Master key should be kept offline at all times and is only used to certify your other keys, namely encryption, signing, and authentication subkeys that will be stored on the Yubikey and used for all other purposes. In addition, the Master Key will be used to revoke or create new subkeys.
When creating your key you’ll be prompted to enter a password. Enter a good password and make sure you write it down and store it securely. If you forget you’ll have to start over.
Creating the master key
We’ll use GPG to create a master key with
Certify only authority
gpg --expert --full-gen-key
Select 8: RSA (set your own capabilities)
Select E to toggle off the Encrypt capability, which will leave you with only Sign + Certify.
Select S to toggle off the Sign capability, which leaves only Certify
Set a 4096 bit key size, if you have some specific need you can chose 2048 bit for older hardware
No need to set an expiration date for this key
Enter your name, email and a comment to setup the UID.
Setup a passphrase.
Once the key is generated you should note the
which you’ll use later
Create your subkeys
Here we will edit the Master Key to add a number of subkeys
gpg --expert --edit-key $KEYID
These subkeys will be loaded onto your Yubikey and used for all the daily purposes.
(4) RSA (sign only)
Set key expiration for 1 year. This can be extended later with your master key when required. By setting an expiration date you can limit any damage from a compromised subkey.
Now add another key following a similar process
(6) RSA (encrypt only)
Choose 4096 bits
Set the key expiration to 1 year again
Finally we create an authentication only subkey. GPG doesn’t provide a default key for this so we create our own
(8) RSA (set your own capabilities)and toggle the options until only
Choose 4096 bits again
Set a 1 year expiration
Verify the keys
You can verify your keys
gpg --list-secret-keys -------------------------------- sec# rsa4096/0x20D0685093466FC7 2018-10-20 [SC] [expires: 2019-10-21] Key fingerprint = 5DC0 E5C9 AD73 DC63 D61D 7445 20D0 6850 9346 6FC7 uid [ unknown] Shankar Kulumani (YubiKey) <email@example.com> ssb> rsa4096/0x58AA35F282289879 2018-10-20 [S] [expires: 2019-10-21] ssb> rsa4096/0x65C3E441CAA89126 2018-10-20 [E] [expires: 2019-10-21] ssb> rsa4096/0xABCD933DE083D57D 2018-10-20 [A] [expires: 2019-10-21]
If you’d like you can add additional emails to your key using the
Generate a revocation certificate
It’s a good idea to generate a revocation certificate in case GPG didn’t do it by default
gpg --output revocation.asc --gen-revoke $KEYID
Backing up your keys
This step is very IMPORTANT because once your keys are on the Yubikey it will be impossible to remove. Without backing these up if you lose your Yubikey you will lose access to anything secured by your keys!!
First we’ll export the GPG keys to an ASCII armored format
gpg --armor --output private_key.gpg --export-secret-key $KEYID gpg --armor --output sub_keys.gpg --export-secret-subkeys $KEYID gpg --armor --output public_key.gpg --export $KEYID
Take all of these files (private, sub, public, and revocation) and backup them up on a seperate USB drive. It’s important these files are safe and stored offline. Keep them safe with your important documents, such as your passport and birth certificate.
The public key will need to be loaded onto any of your systems and shared with the world. Move that to an easily accessible location. One option is to upload your public key to Keybase. Also consider creating a paper backup
Personalizing your Yubikey
The first step is to use GPG to enable the YubiKey to be used as a smartcard. In addition, we’ll change the default and admin PINs on the Yubikey. The default PIN is used to utilize your keys while the admin PIN is used to unlock the card and perform more critical operations.
Plug in your YubiKey:
- Once in GPG type
- Follow the prompts to modify the Admin PIN (selection
- You can also update
loginand finally type
Transfer your keys to the YubiKey
keytocard operation is destructive and will remove the key from your sytem and place it securely onto the YubiKey.
Ensure you have made backups before completing this step.
gpg --edit-key $KEYIDto display your master (certify), signing, encryption, and authentication keys
key 1to select the Signing key (indicated by a
*) followed by
1to transfer to the YubiKey
- Deselect the key using
key 1and select the next key with
key 2and then transfer using
keytocardand pick the appropriate key type
- Repeat for the authentication key
- Once all keys are saved enter
Finally verify the keys on the card using
The keys should be indicated by
ssb> indicating that only a stub exists on the system and the keys are located on the card
sec# rsa4096/0x20D0685093466FC7 2018-10-20 [SC] [expires: 2019-10-21] Key fingerprint = 5DC0 E5C9 AD73 DC63 D61D 7445 20D0 6850 9346 6FC7 uid [ unknown] Shankar Kulumani (YubiKey) <firstname.lastname@example.org> ssb> rsa4096/0x58AA35F282289879 2018-10-20 [S] [expires: 2019-10-21] ssb> rsa4096/0x65C3E441CAA89126 2018-10-20 [E] [expires: 2019-10-21] ssb> rsa4096/0xABCD933DE083D57D 2018-10-20 [A] [expires: 2019-10-21]
You should have already backed up your keys previously. If not, now is the time to export your public key to share with the world. You will need this public key on every system you want to use your YubiKey.
gpg --export --armor $KEYID > /tmp/public_key.gpg
Make sure you have the following before leaving your Live Image
- Backed up your master key, subkeys, revocation certificate, and public key
- Saved your YubiKey PIN
- Saved the password for your master key
Using your keys
You can reboot into the Live Image, or onto another system to test your keys
sudo apt-get update sudo apt-get install gnupg2 gnupg-agent pcscd curl
Copy the hardended
gpg.conf file to your system
mkdir ~/.gnupg ; curl -o ~/.gnupg/gpg.conf https://raw.githubusercontent.com/drduh/config/master/gpg.conf chmod 600 ~/.gnupg/gpg.conf
Import the public key from your backup
gpg --import /tmp/public_key.gpg
Trust the master key (since it’s your own key)
gpg --edit-key $KEYID followed by
trust and ultimate trust.
Insert your Yubikey and enter
gpg --card-status to see something similar to the following
Sex ..............: male URL of public key : https://keybase.io/skulumani/pgp_keys.asc?fingerprint=5dc0e5c9ad73dc63d61d744520d0685093466fc7 Login data .......: email@example.com Signature PIN ....: not forced Key attributes ...: rsa4096 rsa4096 rsa4096 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 3 3 Signature counter : 29 Signature key ....: 1B79 243F 477B 0569 EA44 56FC 58AA 35F2 8228 9879 created ....: 2018-10-20 19:13:49 Encryption key....: F5F1 51D1 1BDA 4FC6 7CF6 5FA9 65C3 E441 CAA8 9126 created ....: 2018-10-20 19:15:17 Authentication key: 7973 F74B 9489 FFAA EE75 804C ABCD 933D E083 D57D created ....: 2018-10-20 19:17:38 General key info..: sub rsa4096/0x58AA35F282289879 2018-10-20 Shankar Kulumani (YubiKey) <firstname.lastname@example.org> sec# rsa4096/0x20D0685093466FC7 created: 2018-10-20 expires: 2019-10-21 ssb> rsa4096/0x58AA35F282289879 created: 2018-10-20 expires: 2019-10-21 card-no: 0006 07761351 ssb> rsa4096/0x65C3E441CAA89126 created: 2018-10-20 expires: 2019-10-21 card-no: 0006 07761351 ssb> rsa4096/0xABCD933DE083D57D created: 2018-10-20 expires: 2019-10-21 card-no: 0006 07761351
sec# means that the master key is not available (since it’s stored offline)
If you see something about
none key info, this means you need to import your public key.
Basic GPG usage
Here are some examples on how to use your YubiKey
- Encrypt to yourself
echo "message" | gpg --encrypt --armor --recipient $KEYID
- Encrypt to multiple recipients, just use multiple
echo "message" | gpg --encrypt --armor --recipient $KEYID --reciepient $KEYID_1
If you don’t use your own key, you won’t be able to later decrypt
cat encrypted_message.txt | gpg --decrypt --armor
- Signing a message
echo "message signed" | gpg --armor --clearsign --default-key $KEYID
- Verify a signature
cat signed_message.txt | gpg --verify
You should a
Good signature and if it complains you can set the trust level of your own key.
Setting up Git to use your GPG keys for SSH access and signing
We will use
gpg-agent to handle keys and use it instead of
First download a hardened configuration for
curl -o ~/.gnupg/gpg-agent.conf https://raw.githubusercontent.com/drduh/config/master/gpg-agent.conf
or copy the following to
use-standard-socket enable-ssh-support pinentry-program /usr/local/bin/pinentry-curses default-cache-ttl 60 max-cache-ttl 120
Add the following to your shell rc files to utilize
# set gpg stuff export GPG_TTY=$(tty) unset SSH_AGENT_PID export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
To use your Yubikey for SSH, copy the following to your servers
$ ssh-add -L ssh-rsa AAAAB3NzaC1yc2EAAAA[bunch of random stuff] cardno:000607761351
It also makes sense to explicitly use this identity for servers you’ve setup by modifying your
First save this identity
ssh-add -L | grep "cardno:" > ~/.ssh/id_rsa_yubikey.pub
~/.ssh/config to use this identity
Host github.com IdentitiesOnly yes IdentityFile ~/.ssh/id_rsa_yubikey.pub
Test your connection:
ssh email@example.com -vvv
Git signing with your YubiKey
Tell Git to use your key
git config --global user.signingkey $KEYID
Now sign your commits/tags with the
-S option which will automatically poll the YubiKey.
Upload the public key to your Github account to get that sweet verified image: