All Articles

Setting up keepassxc with yubikey

showing the unlock screen of keepassxc

I use keepassxc to store my passwords. Up until now I have been using Password + Keyfile as the database credentials used to unlock my keepass database, where keyfile has been mostly used as a salt rather than an actual secrets. I store a backup of this keyfile in various online accounts. Because of this I’ve never been comfortable storing the passwords anywhere online, as it would only require cracking my password. Adding the yubikey secret to the credentials should add an offline factor that will be very difficult to compromise.

For the setup I’ll use the yubikey’s challenge-response mode, but what is it? I would like to ensure that it is something that cannot be extracted from the yubikey.

[…] Challenge-response, on the other hand, begins with a “challenge” that a host sends to the YubiKey. The YubiKey receives the challenge (as a byte array) and “responds” by encrypting or digesting (hashing) the challenge with a stored secret key and sending the response code back to the host for authentication.

Sounds good! Most of this will follow a reddit post by Mirrormaster85 on the KeePass reddit, but I prefer having my own instructions to follow to be safe. I leave this with some room for improvement as I’ll likely keep iterating on this setup.

Setting up the yubikey for challenge-response HMAC

First, I check the yubikey slots - it’s probably best to check that it wont overwrite something.

$ ykman otp info
Slot 1: programmed
Slot 2: empty           # << looks good to me!

Next I generate a new chalresp secret. Ensure that you save the randomly generated key marked as [secret] - this will be your backup.

$ ykman otp chalresp -g 2
Using a randomly generated key (hex): << [secret] >>
Program a challenge-response credential in slot 2? [y/N]: y

Note: you can also use `-t option if you want to require to physically press the yubikey in order to pass the challenge. I chose not to as I think the additional step is not worthwhile this time. It mainly protects against an attacker that would already be on your machine, in which case I don’t think it entirely prevents that attack either. The main threat I worry about is an offline attack where my kdbx file has leaked somehow.

As expected Slot 2 should now show as programmed:

$ ykman otp info
Slot 1: programmed
Slot 2: programmed

Enabling the yubikey credential in KeepassXC

Before enabling the yubikey as a credenital in KeepassXC I make a backup of the database, just in case I manage to lose my keys or accidentally break something while I’m setting this up. This I’ll remove later once I confirmed the setup works. I save this as passwords-backup.kdbx.

To set up the new yubikey:

  1. Unlock your database using your current credentials.
  2. From the top menu, go to Database -> Database Security
  3. Under Challenge-Response set the yubikey - if set up correctly it should be able to detect it:

challenge-response setting in keepassxc

Finally test that the new configuration works by locking and then unlocking the database.

Backing up the Key

To actually back up the challenge-response key I save it in two places:

  1. Inside the password database itself - this will mainly be helpful in case I e.g. get a new yubikey while my current one still works.
  2. Printed as a QR Code / raw text - this I’ll just store in a safe place. Anyone who could steal this could just as likely steal my yubikey.

Recovery

To perform recovery:

  1. Load the QR code (or type the hex manually)
  2. Add the value to the slot via ykman ykman otp chalresp 2 [secret]
  3. Attempt to access the keepass database.

Testing the initial setup

To ensure you are actually using the correct secret, you can test first that the database doesn’t unlock if you use the wrong secret. You can test this (carefully! - ⚠️ Ensure you have taken your backups before testing the setup.) by having the slot reset to a new random key again via ykman otp chalresp -g 2. Then proceed with recovery of your secret to test that the real key works.

Cleaning up

⚠️ Ensure you have taken your offline backups and tested the setup before cleaning up.

Finally I remove the passwords-backup.kdbx as well as any other local copies - QR code, text copy that I created while testing.

Todo

Things I’d like to improve:

  • Research: How does Keepass actually derive the key? If it’s just a hmac of a static key, can’t that be captured?
  • Do a nicer job of storing the offline backup
    • If I am feeling extra paranoid I could additionally encrypt the output before printing with some password.
    • Could also look into using a mnemonic/recovery phrase like niceware or bip39 to make it easier to manually input.
    • Of course I can also laminate the paper to make it more durable
  • Generally threat model / harden my password storage setup - this post only looks at the yubikey part.

References:

https://docs.yubico.com/yesdk/users-manual/application-otp/challenge-response.html

https://support.yubico.com/hc/en-us/articles/360013779759-Using-Your-YubiKey-with-KeePass

https://www.reddit.com/r/KeePass/comments/opx34q/keepassxc_and_yubikeys_setting_up_the/

Published Apr 17, 2024

Security Engineer with a dash of software. Originally from Stockholm, now in Berlin. I like to hack things.