Module 1 of 7

Meet Your YubiKey

Before we type a single command, let's understand what a YubiKey actually is and why you'd go through all this setup.

What's a YubiKey, Really?

Physically, it's a little USB dongle with a gold contact pad. But what's inside is more interesting: a secure element — a tiny computer with its own processor, memory, and cryptographic accelerator. It's designed so that the keys stored inside can never be extracted, even by someone with physical access to the device.

🔒 Secure Element Hardware vault keys never leave OpenPGP Sign / Decrypt / Auth FIDO2 WebAuthn logins OTP One-time passwords OATH TOTP codes Your Computer ↕ USB / NFC Sends crypto requests Receives results only Private key stays 🔒

Why Bother?

Right now, your PGP private keys are files on your hard drive. If someone steals your laptop, they can copy those files and try to crack your passphrase offline with unlimited attempts.

With a YubiKey:

  • Keys never touch your hard drive — they live inside the secure element.
  • Physical possession is required — no YubiKey, no crypto.
  • 3 wrong PIN attempts = lockout — brute force is defeated by the hardware.
  • Optional touch policy — you can require a physical tap before every signature.

What You'll Learn in This Course

🔑 PGP Key Generation 🛡️ YubiKey OpenPGP 🖥️ Kleopatra 🔐 KeePass + YubiKey

Each module builds on the last. By the end, you'll understand the entire chain — from key generation through daily usage and disaster recovery.

🎯 No YubiKey? No Problem

This tutorial simulates every command and its output. You can follow along completely, then repeat with your real hardware when you're ready. The terminal buttons let you "run" commands and see exactly what they'd output.

Let's See the Real Thing

When you plug in a real YubiKey and check it, this is what you'd see. Go ahead and click the button below.

terminal — bash
$ gpg --card-status

Knowledge Check

What makes a YubiKey different from storing keys on your hard drive?

Module 2 of 7

Install the Software Stack

Before we can use a YubiKey for PGP, we need to install the software that talks to it. Think of it as building a communication chain from your computer down to the hardware.

The Communication Chain

gpg / Kleopatra Your PGP commands scdaemon GPG's smartcard driver pcscd System smartcard service YubiKey (USB CCID) ↓ Linux Kernel (USB / CCID driver) ↓

If any link in this chain breaks, the YubiKey won't be detected. We'll install all of them now.

Step 1: Install the Packages

Open a terminal and run this command (click it to see what the output looks like):

terminal — bash
$ sudo dnf install gpg gpgme pinentry-gtk scdaemon pcsc-lite pcsc-lite-ccid pcsc-tools opensc kleopatra yubikey-manager

📦 Not on Fedora?

If you're on Debian/Ubuntu: use sudo apt install gnupg2 scdaemon pcscd pcsc-tools opensc kleopatra yubikey-manager

If you're on Arch: use sudo pacman -S gnupg pcsc-lite ccid opensc kleopatra yubikey-manager

Step 2: Start the Smartcard Service

Even after installing, the service needs to be running. This is one of the most common gotchas:

terminal — bash
$ sudo systemctl enable --now pcscd
$ sudo systemctl status pcscd

Step 3: Verify the YubiKey Is Detected

Plug in your YubiKey (or pretend to) and run:

terminal — bash
$ ykman info
$ gpg --card-status

⚠️ Common Pitfall

If gpg --card-status returns No such device even after installing everything: first make sure pcscd is running (sudo systemctl restart pcscd), then kill and restart GPG's internal daemon with gpgconf --kill scdaemon. If you see an "inappropriate ioctl" error on Fedora, install opensc and remove gnupg-pkcs11-scd if present.

Knowledge Check

Which daemon is the system-level smartcard service that talks to the YubiKey hardware?

Module 3 of 7

Generate Your PGP Keys

Time to create your cryptographic identity. We'll generate a master key (which stays safely offline) and three subkeys (which will live on the YubiKey).

The Master / Subkey Architecture

🔑 Master Key (C) RSA 4096 — Certify only ⬇ signs subkeys ⬇ ✍️ Signing (S) Emails, git, files 🔒 Encryption (E) Decrypt messages 🔐 Authentication (A) SSH logins ⬇ All 3 subkeys moved to YubiKey ⬇

Why this complexity? Simple: if a subkey is compromised, you revoke just that subkey and issue a new one — your identity (the master key fingerprint) stays the same. If the master key does the daily work and gets compromised, your entire identity is gone.

Step 1: Generate the Master Key

terminal — bash
$ gpg --expert --full-generate-key

Here's what you'd answer during the interactive prompts:

PromptYour AnswerWhy
Key type(8) RSA (set your own capabilities)We want a master key that can ONLY certify
CapabilitiesToggle Sign OFF, Encrypt OFF, leave Certify ONMaster key does one job: certify subkeys
Key size4096Strongest RSA commonly supported
Expiration2ySafety net — can extend later with master key
Name / EmailYour name and emailThis is your public identity on the key
PassphraseStrong passphrase (12+ chars)Protects your master key backup

💡 Why "Certify Only"?

The Certify flag (C) means this key can sign other keys — that's it. It cannot sign files, encrypt messages, or authenticate SSH sessions. This is intentional: the master key stays in a safe (or encrypted USB) and only comes out when you need to extend expiry, revoke a subkey, or certify someone else's key.

Step 2: Add Subkeys

Now we add three subkeys — one for each capability. We do this from inside the GPG key editor.

terminal — bash (gpg key editor)
$ gpg --expert --edit-key 0xABCDEF1234567890

The three addkey commands you'll run (one at a time):

gpg> prompt

Step 3: Create a Revocation Certificate

This is your emergency parachute. If your master key is ever compromised, this cert lets you tell the world "this key is no longer mine." Do not skip this.

terminal — bash
$ gpg --output ~/revoke-0xABCDEF1234567890.asc --gen-revoke 0xABCDEF1234567890

Knowledge Check

What is the primary purpose of the master (Certify) key?

Order the steps for creating a PGP key with YubiKey support:

Module 4 of 7

Prepare the YubiKey

Before we load keys onto the YubiKey, we need to configure its PINs and security policies. The YubiKey comes from the factory with default PINs that everyone knows — changing them is step one.

The Three Secrets

SecretDefaultWhat It DoesUsed For
User PIN123456Unlocks the card for daily useSigning, decrypting
PUK12345678Unblocks a locked User PINRecovery (3 wrong PINs → locked)
Admin PIN12345678Unlocks administrative operationsKey import, touch policy, reset

🔴 CRITICAL: Change Defaults Immediately

If you use your real YubiKey with default PINs, anyone who picks it up can use your keys. The defaults are public knowledge — they're in Yubico's documentation.

Step 1: Change the PINs

terminal — bash (gpg --edit-card)

The PIN menu has four options:

#ActionDo This First
1Change User PINAfter Admin PIN — sets your daily unlock code
2Unblock PINOnly if PIN is locked (needs PUK)
3Change Admin PINDo this FIRST — most sensitive
4Set Reset CodeOptional backup unlock method

🎯 PIN Best Practices

Use a random 6-8 digit number for the User PIN — something you can type quickly but isn't your birthday. Use a long random string for the Admin PIN (store it in your password manager). The Admin PIN is only needed during setup, so it can be complex.

Step 2: Set the Key Size

The YubiKey defaults to RSA 2048-bit keys. To use the 4096-bit keys we generated, we need to tell the YubiKey to expect that size:

gpg/card> (admin mode)
gpg/card> key-attr

You'll be prompted three times — once for each key slot (SIG, DEC, AUT). For each, select:

  1. 1 — RSA
  2. 1 — 4096

Step 3: Set Touch Policy

This is one of the YubiKey's best features. You can require a physical tap on the YubiKey before it performs any crypto operation. Options:

PolicyMeaningBest For
OffNo touch needed — PIN onlySSH auth (frequent, background)
OnTap required for every operationSigning (maximum security)
CachedTap once, app reuses for ~15 secondsBatch decryption (balance)
FixedLike On, but can't be changed without factory resetHigh-security / threat model
Cached-FixedTap once, cached ~15s, policy is permanentUse-once-per-session + permanent
terminal — bash (ykman)

Step 4: Factory Reset (If Needed)

If your YubiKey has been used before — or you got it second-hand — you might want a clean slate. This wipes everything from the OpenPGP applet:

terminal — bash
$ ykman openpgp reset

⚠️ This Destroys All Keys on the Applet

Factory reset wipes the signing, encryption, and authentication keys from the YubiKey. It does not affect FIDO2, OATH, or OTP slots — just the OpenPGP applet. After reset, unplug and replug the YubiKey, then verify with gpg --card-status.

Knowledge Check

What happens if you enter the wrong User PIN 3 times?

Which touch policy requires a physical tap for every crypto operation and cannot be changed without a factory reset?

Module 5 of 7

Move Keys to the YubiKey

This is the critical step. We transfer the subkeys from your hard drive into the YubiKey's secure element. After this, the private key material exists only on the YubiKey. Your computer keeps "stubs" — pointers that say "this key is on card #XXXX."

🧠 What's a Stub?

After keytocard, GPG replaces the private key file with a stub file containing just: the public key, the card serial number, and which slot the key is in. The actual private key data no longer exists on your computer's storage. If you lose the YubiKey, the stubs are useless — you'd need your backup to recover.

Step 1: Check Your Key Structure

terminal — bash
$ gpg --list-secret-keys --keyid-format=long 0xABCDEF1234567890

You should see one sec (master key) and three ssb entries (subkeys). No > symbols yet — that comes after we move them.

Step 2: Move Each Subkey

Open the key editor and move subkeys one at a time. Each subkey gets its own slot on the YubiKey.

The ritual (repeat for each subkey):

  1. key N — selects subkey N (you'll see an asterisk *)
  2. keytocard — moves it to the YubiKey
  3. Choose the slot (1=SIG, 2=ENC, 3=AUT)
  4. Enter your master key passphrase, then the Admin PIN
  5. key N — deselects it
gpg> key editor

Step 3: Verify the Move

terminal — bash
$ gpg --list-secret-keys --keyid-format=long 0xABCDEF1234567890

Look for the > symbol after each ssb and the card-no: line. That's your confirmation: the private key is on the YubiKey, and your computer only holds stubs.

Step 4: Test Your Setup

terminal — bash

🧪 What to Expect with a Real YubiKey

When you run the test sign command, a pinentry window will pop up asking for your YubiKey PIN. If you set touch policy to on, the YubiKey's LED will blink — tap the gold contact. The signed output appears in your terminal.

Knowledge Check

What does the > symbol mean next to a subkey in gpg --list-secret-keys?

Which PIN do you enter when moving a key to the YubiCard?

Module 6 of 7

Using Kleopatra Day-to-Day

Kleopatra is the graphical frontend for GPG. Once your YubiKey is set up, it gives you a visual interface for encryption, signing, and certificate management — all backed by the same keys on your YubiKey.

What Kleopatra Shows You

Launch it from your application menu or run kleopatra in a terminal. You'll see your key listed in the main window:

kleopatra — main window
File   View   Tools   Settings   Help
Name / Email Key ID Status
✅ Johnny <johnny@example.com> 0xABCD…7890 Valid ✓
🔑 RSA 4096  |  📋 Subkeys: S E A  |  🆔 YubiKey: card-no 0006XXXXXX
Your certificate is valid and your YubiKey is detected.

Encrypting a File

  1. Right-click the file → Encrypt with OpenPGP (you need the recipient's public key imported)
  2. Select the recipient from the list
  3. Check "Encrypt for me too" so you can decrypt it later
  4. Click Encrypt — a .gpg file is created

Decrypting a File

  1. Right-click a .gpg or .pgp file → Decrypt with OpenPGP
  2. The pinentry window asks for your YubiKey PIN
  3. If touch is enabled, the YubiKey LED blinks — tap it
  4. The decrypted file appears alongside the encrypted one

🔍 What's Happening Under the Hood?

Kleopatra calls gpg --decrypt. GPG reads the file, sees it was encrypted to your encryption subkey, and looks up that subkey in its keyring. It finds the stub pointing to your YubiKey. GPG sends the encrypted data to the YubiKey through scdaemon, which asks for your PIN (and optionally a touch). The YubiKey decrypts inside its secure element and returns the result. The private key never leaves the YubiKey.

Signing a File

  1. Right-click → Sign with OpenPGP
  2. Choose signature type:
    • Detached — separate .sig file (best for software distribution)
    • Clearsign — text stays readable, signature wrapped around it
    • Combined — signature embedded in the file (binary)
  3. Enter YubiKey PIN and tap

Verifying a Signature

  1. Double-click a .sig or .asc file
  2. Kleopatra shows:
    • Good signature — file is authentic
    • Bad signature — tampered
    • ⚠️ No known public key — you need the signer's public key

Importing Other People's Keys

To encrypt for someone, you need their public key:

  • From a file: File → Import → select .asc
  • From a keyserver: File → Lookup on Server → enter email
  • Drag-and-drop: Drop the .asc onto Kleopatra's window

Knowledge Check

When you encrypt a file in Kleopatra and select a recipient, what key do you need from them?

Why does a .gpg file appear when you encrypt, and then get decrypted back to the original?

Module 7 of 7

Unlock KeePass with Your YubiKey

This last piece uses a completely different YubiKey feature — not OpenPGP, but the OTP slot's HMAC-SHA1 challenge-response capability. It's like giving your KeePass database a second lock that only this specific YubiKey has the key to.

🧠 Important: Separate Systems

Your PGP keys live in the OpenPGP applet. KeePass unlock uses the OTP applet's slot 2. They run on the same physical YubiKey but in completely separate, independent subsystems. Configuring one has zero effect on the other.

How Challenge-Response Works

💻 Your Computer KeePassXC sends random challenge challenge 🔑 YubiKey (Slot 2) HMAC-SHA1(secret, challenge) = response response 🔓 Database unlocks only if response matches expected value

KeePassXC stores a random challenge in the database header. To unlock, it sends that challenge to the YubiKey, which computes HMAC-SHA1 using the secret stored in slot 2. If the response is correct, the database decrypts. Without the physical YubiKey with that specific secret, the database cannot open.

Step 1: Program YubiKey Slot 2

This stores a random 20-byte secret in the YubiKey's OTP slot 2. The key detail: --generate creates the secret on the device itself — it never travels over USB.

terminal — bash
$ ykman otp chalresp --generate 2

⚠️ Slot Confusion

Slot 2 is the long-press slot on the YubiKey (hold the gold contact for a few seconds). If you already use slot 2 for something (like a static password), choose slot 1 instead: ykman otp chalresp --generate 1. This will overwrite whatever is in that slot.

Step 1b: Program Slot 1 as Backup (Optional but Smart)

If you have a second YubiKey or want to use slot 1 for redundancy, program it now. Slot 1 is the short-tap slot — a quick touch triggers it. This gives you two unlock paths on the same YubiKey, keeping one as a fallback.

terminal — bash
$ ykman otp chalresp --generate 1

💡 Why Both Slots?

Slot 2 (long-press) is your daily driver. Slot 1 (short-tap) backs it up on the same device. If slot 2 ever gets corrupted or you accidentally overwrite it, slot 1 saves you. For true hardware redundancy, program a second YubiKey with ykman otp chalresp 2 <hex> using the backup procedure below.

Step 2: Link KeePassXC to the YubiKey

Assuming you have KeePassXC installed:

terminal — bash
$ sudo dnf install keepassxc

Step 3: Add YubiKey to a Database

New database:

  1. KeePassXC → Database → New Database
  2. Set a strong master password (this is still your primary credential)
  3. Under Master Key, check YubiKey Challenge-Response
  4. Click Detect — it should find your YubiKey
  5. Save the database

Existing database:

  1. Open your database (with your current password)
  2. Database → Database Settings → Security → Master Key
  3. Click Add additional protection → YubiKey Challenge-Response
  4. Detect, save, and test by reopening

What Unlocking Looks Like

Here's a simulated KeePassXC unlock dialog. Click through the steps to see how a YubiKey-authenticated unlock works in real time.

keepassxc — unlock vault.kdbx
🔒
Unlock Database
Master Password:
••••••••••••
YubiKey:
Not detected

The real KeePassXC dialog looks very similar: you enter your master password, it detects the YubiKey automatically, and you touch the gold contact to respond to the challenge. No PINs, no codes — just possession of the physical key.

Backup Strategy: You MUST Plan for Failure

The tradeoff for strong security: if you lose the only YubiKey with the secret, your database is gone forever. You need a plan.

🔑
Primary YubiKey
Daily driver
🔄
Backup YubiKey
Same secret!
📋
Paper Backup
Hex secret in safe

Option 1: Backup YubiKey — Pre-Generate a Known Secret

The safest approach: generate the hex secret yourself before programming either YubiKey, then program both devices with the same key.

terminal — bash
$ openssl rand -hex 20
  1. Program your primary YubiKey (slot 2): ykman otp chalresp 2 <hex>
  2. Program slot 1 as a backup on the same device: ykman otp chalresp 1 <hex>
  3. Program a second YubiKey with the same hex key: ykman otp chalresp 2 <hex>
  4. Store the backup YubiKey somewhere safe (safe deposit box, locked drawer)

Option 2: Emergency Sheet (KeePassXC feature)

KeePassXC can generate a printable PDF with a one-time recovery code that bypasses the YubiKey requirement entirely. Click below to simulate:

keepassxc — emergency sheet

Option 3: Print the hex secret for cold storage

Before programming, save the hex output from openssl rand -hex 20 and write it on paper. Store it somewhere fireproof. You can recreate the slot with ykman otp chalresp 2 <hex> on any YubiKey.

🔴 Important Security Note

The hex key should be generated on a trusted, offline-capable machine. Once you use it, the hex string exists in your shell history. Clear it immediately: history -c && history -w. Then consider overwriting your ~/.bash_history file with shred -u ~/.bash_history to prevent forensic recovery. Store the hex string in an encrypted password manager — not as a plain text file.

Knowledge Check

What makes the KeePass + YubiKey setup secure even if someone has your database file?

What's the safest way to create a backup for your KeePass YubiKey setup?

If you generate a hex key with openssl rand -hex 20 and program your YubiKeys, what must you do with the hex string afterward?

🏆

You've Completed the Course

You now understand the full chain — from key generation through YubiKey setup, Kleopatra daily use, and KeePass integration.

Here's what you've learned:

🔑 RSA 4096 key generation 🛡️ Master / Subkey architecture 💳 Smartcard PINs & security 👆 Touch policy configuration 📦 keytocard key transfer 🖥️ Kleopatra sign/encrypt/verify 🔐 KeePass challenge-response 💾 Backup & recovery planning

Ready for the real thing? Grab your YubiKey, open the full reference guide at ~/leVAULT/YubiKey-PGP-Guide/, and follow along step by step. Every command in this tutorial works on real hardware.