Skip to content
This repository has been archived by the owner on Dec 9, 2021. It is now read-only.

RFC: Add YubiKey HMAC-SHA1 Challenge-Response #52

Closed
wants to merge 16 commits into from

Conversation

kylemanna
Copy link

Overview

This pull request adds support for YubiKey, a USB authentication device commonly used for 2FA. Support is added by configuring a YubiKey slot to operate in HMAC-SHA1 challenge-response mode. The mechanism works by submitting the database master seed as a challenge to the YubiKey which replies with a HMAC-SHA1 cryptographic hash. The resultant hash is then hashed with the other keys (password, keyfile) to generate the final key used to encrypt the database.

I have uploaded a few screenshots to imgur.

Details

  • Breaks the ability to open the KeePass2 database by anything other then KeePassX with YubiKey support. Perhaps KeePass2 could open it with a plugin, but I didn't look at it.
  • Implemented using YubiKey HMAC-SHA1 configuration and operates completely offline.
  • The master seed is used as the challenge and changes on every write to help partially combat replay attacks as it's regenerated every time the database is saved.
  • YubiKey User Input Mode can be configured in a blocking or non-blocking mode.
    • Non-blocking mode is preferred such that the challenge-response can quickly be issued and returned despite being slightly less secure due to lack of user input.
    • Blocking mode works, but doesn't provide feedback to the user, so the UI appears to hang even though it's waiting. I preferred simplicity for the initial code.
  • Upon generation of the HMAC key, it can be saved and cloned to other YubiKey devices to prevent loss of database access to loss or destruction of the YubiKey hardware. This is highly recommended.
  • Only supports the first detected YubiKey Plugged in, but does enumerate both configuration slots on the device. I only have one YubiKey and can't test multiple (yet).
  • The libyubikey and ykpers-1 libraries are necessary for support. These libraries are detected at compile time to enable support and necessary at run-time.
  • Tested on Arch Linux and Mac OS X Mavericks with and without YubiKey support
    • Arch Linux via AUR:
      • libyubikey: 1.11-1
      • yubico-c-client-git: 2.12.r2.g539af75-1 and 2.12.r3.g262a19c-1
      • yubikey-personalization-git: 1.14.2.r5.ga7392f0-1 and 1.15.1.r10.g52890f6-1
    • Mac OS X Mavericks via Homebrew:
      • libyubikey: stable 1.11
      • ykpers: stable 1.15.1
    • Test hardware is a YubiKey Standard with firmware version 2.2.3.
  • Adds challenge-response combo box to support other mechanisms in the future
  • Can be disabled explicitly at compile time with cmake -DCMAKE_DISABLE_FIND_PACKAGE_YubiKey=TRUE

Quick Start Guide

  1. Install necessary libraries to appease KeePassX's CMake configuration step

    -- The following OPTIONAL packages have been found:
    * YubiKey
    
  2. Install yubikey-personalization-gui and configure slot 2 for HMAC-SHA1 challenge-response. Be sure to write the configuration. Optionally it can be programmed via the command line.

  3. Start up KeePassX with the YubiKey inserted and the challenge-response form of the DatabaseOpenWidget ChangeMasterKeyWidget should enable themselves asynchronously listing the inserted YubiKey. Review screenshots on imgur for the configuration tool.

Upstream / Reference

@kylemanna kylemanna changed the title RFC: Add Yubikey HMAC-SHA1 Challenge-Response RFC: Add YubiKey HMAC-SHA1 Challenge-Response May 26, 2014
@OJ
Copy link

OJ commented May 26, 2014

Nice addition! One of the things that is disappointing about some services is that they only allow one key to be registered with the application, which means that you're screwed if you lose that key. It'd be nice to be able to associate a back up key as well.

Does this PR provide support for multiple keys?

Cheers!

@kylemanna
Copy link
Author

@OJ You can't use multiple encryption keys. Instead you can generate and save the 20 byte HMAC secret prior to programming the YubiKey. You could then program an infinite number of other YubiKeys with the same secret. See the screenshot in the PR showing the Yubico GUI tool, note the key field.

Alternatively, the HMAC-SHA1 process could probably be done manually if the secret was saved. That is to say that if you saved the secret, you could hack together some KeePassX code to unlock your database without the physical hardware. This would only be done in an emergency.

@OJ
Copy link

OJ commented May 26, 2014

@kylemanna Thanks for the response mate. Back when I got my key I wasn't able to do this (but that was a while ago) and so I had to go with the "add multiple keys" approach. Things appear to be a bit different now. Thanks for the education. Cheers!

@ghost
Copy link

ghost commented May 27, 2014

@kylemanna

you could hack together some KeePassX code to unlock your database without the physical hardware. This would only be done in an emergency.

FWIW, I think the "emergency process" should be defined here. I'd be really nervous about losing my key and losing access to the database (but I guess this is the same with the file.key on a USB stick?).

Edit: missed this

Upon generation of the HMAC key, it can be saved and cloned to other YubiKey devices to prevent loss of database access to loss or destruction of the YubiKey hardware. This is highly recommended.

Is there something that I can print out on a piece of paper and put in a safe somewhere? Something like the 2FA recovery codes GitHub provides.

@ghost
Copy link

ghost commented May 27, 2014

Someone on HN mentioned http://sourceforge.net/projects/keechallenge/ for KeePass2. Is there a way this could be compatible?

@kylemanna
Copy link
Author

@voltagex A recovery mode could be added, but that's outside the scope of this PR. I'd rather people just purchase and use 2 YubiKeys, that way the HMAC secret is (most likely) secure rather then potentially sitting in a plain text file somewhere... forgotten. If there is more interest, there isn't any reason a recovery mode couldn't be added where the HMAC secret could be input.

You can easily print out the YubiKey's HMAC secret, see the screenshots in my pull request of the Yubico Personalization tool, it has my test HMAC secret cleary visible.

As for KeeChallenge, it's different in the actual implementation according to the README:

Your secret is used as the key to encrypt the database. In order to avoid storing the secret in plain text, we generate a challenge-response pair ahead of time. The challenge is stored to be issued on the next login and the response is used as an AES256 key to encrypt the secret. All relevant data is stored in a xml file in the same directory as your database.

KeeChallenge is using the HMAC-SHA1 feature in the same general manner, but storing an extra xml file and using the HMAC secret (ironically stored encrypted in the XML file) to unlock the KeePass DB. The KeePass plugin API may not have access to the master seed or it didn't occur to the author. I personally prefer my implementation as I don't want to have an extra xml file to lose/corrupt.

Additionally, I derive the final key by hashing the HMAC response + password + key file. His authentication scheme appears to be just the YubiKey encrypting it's own internal secret which is then used to unlock the KeePass database.

A potential attack against KeeChallenge might be to grab the HMAC secret from memory after it's decrypted from the XML file and then circumvent all security by using recovery mode. With my implementation, the HMAC secret is in memory only once when writing the configuration to the YubiKey(s) (which for the paranoid, can be done offline).

At least that's how it appears with the initial review of the code.

On a side note, KeeChallenge appears to handle the GUI operation (particularly blocking mode) better then mine currently does.

@tr37ion
Copy link

tr37ion commented May 28, 2014

@kylemanna I really appreciate your contribution! Great work. Thank you.

If there are concerns to loose the key it is always recommended to have two Yubikeys and store the backup secret offline or on paper. Buying two of them shouldn't be a problem compared to the value you have probably stored in Keepassx. Moreover, Yubikeys are physically well build and even function under water if USB slots would :)

Yubikey security: http://www.yubico.com/2014/04/improvements-physical-yubikey-attacks/

Btw. Yubico recently published YubiX, an open source authentication solution: http://www.yubico.com/develop/open-source-software/yubix/

@mario-tux
Copy link

A good point on using KeeChallenge is that it has now a counterpart on an Android-client (Keepass2Android). Using it and Keepass (mono-version on linux...) it is possible to use an HMAC-SHA1 based DB unlock (off-line) using my yubi neo key.
I hate mono applications and keepass on linux looks horrible but can't find another way to use HMAC-SHA1 based DB unlock on Linux and Android. Any suggestions?!

@fabian-z
Copy link

@kylemanna: Thank you for your good work!
Great addition to keepassx - Compiling & working flawless for me with multiple yubikeys. GUI interaction is feeling good - well, if you don't use blocking mode. A little popup stating e.g. "Touch YubiKey to continue" would be optimal from a security and user point of view.

I noticed that database locking does not work as expected - it only checks the password (and/or keyfile) but not the yubi key (I can even remove it unnoticed by keepassx).
Also, DatabaseOpenWidget does not enable Challenge Response asynchronously for me; the yubikey has to be plugged in when starting keepassx.

But perhaps the most serious flaw I found is a database corruption, which is triggered when opening a challenge-response secured database, removing the yubikey and then trying to save the database. The save was not delayed as before with no error and apparently led to database corruption (was reproducable for me)! Could you please adress the corruption problem?

@kylemanna
Copy link
Author

@fabian-z Thanks for the feedback, glad to hear some people have given it a test drive!

The current patch set lacks user feedback (ie the pop-up) and doesn't actively monitor for YubiKey insertions/removals to keep the initial pull request simple. These are things that could definitely be enhanced.

As for the database locking, I never used that feature so I'll have to look in to it.

The YubiKey removal and corruption issue is a big oversight on my part, I'll have to fix that for sure.

@fabian-z
Copy link

@kylemanna Sure, those nice 'lil user friendly popups are not needed until now - I just wanted to give you my full test feedback.

If database save corruption issue is fixed, this pull request can imho be considered pretty stable. Locking support would be optimal, but I actually don't use locking too. Current behaviour is different from what the user may expect, so it could get a security issue in larger environments.

Glad to know you are working on it - I am already eager to give this a shot in long-term use :) If you have any problems reproducing, let me know.

@marcusmoller
Copy link

Will be testing this out ASAP.
Lovely work @kylemanna!

@ghost
Copy link

ghost commented Aug 17, 2014

Hi, thank You for Your work, I am waiting for Yubikey support as I feel increasing uncomfortable having all my sensible information stored in KeePassX with only a password.

I offer You also test support for it on Linux (Debian Wheezy).

@metbril
Copy link

metbril commented Aug 17, 2014

KeePassX provides the possibility to use a key file stored on a
separate medium, something you "have" (much like a Yubikey).

Op Zo aug 17 2014, om 19:00 schreef wodry:

Hi, thank You for Your work, I am waiting for Yubikey
support as I feel increasing uncomfortable having all my
sensible information stored in KeePassX with only a
password.

I offer You also test support for it on Linux (Debian
Wheezy).


Reply to this email directly or [1]view it on GitHub.

References

  1. RFC: Add YubiKey HMAC-SHA1 Challenge-Response #52 (comment)

@ghost
Copy link

ghost commented Aug 17, 2014

Yes, just realized that, too. But I do not really like it. One needs to have an extra usb stick, one has to connect it every time (and I use KeepassX nearly every day) and then disconnect it again at once (because when it is mounted, the attacker can steal the file and then the security is gone). And if the attacker just watches for usb mount and then copies the file, there is no advantage.
One needs an extra second usb stick as backup for the file. Too complicated for too less gain of security in my opinion.

@kylemanna
Copy link
Author

@digineut yeah, what's the state of the keyfile at rest? Readable or offline? It affords the opportunity for the user to get lazy and leave the keyfile exposed in a data backup or stolen from the flash drive as @wodry mentioned. YubiKey would force good security practice.

I'm going to fix the issues @fabian-z pointed out, but want to see if anyone else has opinions / input? Life has consumed too much of my free time so hopefully we can get this cleaned-up and merged? :)

Most importantly I'd like input from @debfx to see what his thoughts are on this feature. It certainly breaks compatibility with the original KeePass and may constitute a fork if that's unacceptable. @debfx Any thoughts on merging this after I fix the YubiKey removal issues described above?

@fabian-z
Copy link

@kylemanna
In the mean time I got my hands dirty with a little patchset to mitigate the database corruption issue. It is not clean yet, reinit of YubiKey fails with segmentation fault on saving if it was not successful on the first attempt. As a quick and dirty fix I used a global variable preventing saving until the database is reopened.
You can have a look in my fork of your keepassx repo, but I synced it with current keepassx master commits for personal use.
The relevant commit is f2d8b60, maybe it can provide you with some pointers for the issue.

@constint
Copy link

constint commented Sep 7, 2014

@kylemanna

Awesome work !
I haven't managed to corrupt the database since your new commits, one thing though :
if I try to close the database, select save, I get the error message, and then the db closes and the changes are wiped. It would be nice to prevent that.

Note : it's not very annoying since you only have to do it once at startup, but if there could be a config option to automaticly check the "challenge response" box if the key is plugged in...

Many thanks again, keep up the good work ;)

@kylemanna
Copy link
Author

@fabian-z Want to give it a shake down now?

@kylemanna
Copy link
Author

@constint thanks!

The problem with error handling is that currently KeePassX doesn't handle write errors as well as I'd like when dealing with external hardware that can do 100s of wacky things. Write it up on my repo fork so it's not forgotten. I've seen another annoying bug due to this, but it escapes me.

For the config issue, write-up on my repo fork and I'll look at adding it. Should be simple. I want to keep this initial pull / merge request as simple as possible.

@fabian-z
Copy link

fabian-z commented Sep 9, 2014

@kylemanna
Sure! Just done with a first quick test drive. Database corruption seems to be properly fixed. Your commits do a way better job than my humble patchset in terms of hotplug. Database locking works reliable, consistent with expected behaviour outlined in kylemanna#1.
I'll surely give it a shot in daily usage and see if I can discover any glitches.

Only issue left was already outlined by @constint. When the YubiKey is not plugged in while closing the database and one decides to save the changes, the error message will appear but closing the database will proceed afterwards, losing the previous changes since the last save. I wrote this up on your fork as kylemanna#4.

Thanks for these awesome fixes!

@ghost
Copy link

ghost commented Nov 7, 2014

What's the status of Yubikey support ? I tried Password Safe Linux-Beta 0.94, which has Yubikey support working, but I could not use it successfully stable, sometimes it works, sometimes not... So I uninstalled it...

@fabian-z
Copy link

fabian-z commented Nov 9, 2014

I would consider it stable since I am using it daily for about 2 months
without any glitches. You just need to mind
kylemanna#4

You can simply compile keepassx with YubiKey support from @kylemanna :
https://github.com/kylemanna/keepassx

If you want latest keepassx master patches, you can always fork your own
copy from his repository and merge masters changes with git.

@neocogent
Copy link

@kylemana, or knowledegable others.
Will this work with RFC4226 (OATH HOTP)? I read that Yubikey supports RFC4226 but I'm not sure if this is the same standard or if there are variants within Yubikey usage. I'm asking because I would like to use an Android phone for 2F. Actually I'd really like to use the new FIDO U2F standard but I gather that's different again. I haven't seen any support for Keepassx listed anywhere.

There is a HTML5 implementation of RFC4226 (like Google Auth) on github and I'd like to use this with Keepassx since it does not require I give out my phone number. See here,

GAuth Authenticator

To quote, "A simple application which generates TOTP tokens when multi-factor authentication is used with your Google account. It implements RFC4226 (HMAC-based OTP) and has been tested to work with Google Authenticator, Dropbox, Dreamhost and Amazon."

@fabian-z
Copy link

This fork/pull request will currently not work with anything else than a
YubiKey in HMAC-SHA1 challenge-response mode - There seems to be a
plugin for legacy KeePass however.

Am 28.11.2014 um 13:59 schrieb Topher Khaew:

@kylemana, or knowledegable others.
Will this work with RFC4226 (OATH HOTP)? I read that Yubikey supports
RFC4226 but I'm not sure if this is the same standard or if there are
variants within Yubikey usage. I'm asking because I would like to use an
Android phone for 2F. Actually I'd really like to use the new FIDO U2F
standard but I gather that's different again. I haven't seen any support
for Keepassx listed anywhere.

There is a HTML5 implementation of RFC4226 (like Google Auth) on github
and I'd like to use this with Keepassx since it does not require I give
out my phone number
. See here,

GAuth Authenticator
https://github.com/gbraad/html5-google-authenticator/wiki

To quote, "A simple application which generates TOTP tokens when
multi-factor authentication is used with your Google account. It
implements RFC4226 (HMAC-based OTP) and has been tested to work with
Google Authenticator, Dropbox, Dreamhost and Amazon."


Reply to this email directly or view it on GitHub
#52 (comment).

@neocogent
Copy link

@fabian-z
Thanks for your reply. Having thought about it a bit I see that OTP Authentication is quite useless for this situation as the encrypted database is present and wouldn't depend on the OTP. Hence, any malware that could intercept the password would not need the OTP anyway. Silly me.

@kylemanna
Copy link
Author

@tkhaew It's not implemented in traditional sense of an OTP mechanism. Traditional OTP mechanisms are used for authentication. This implementation derives an encryption key from a HMAC-SHA1 mechanism integrated in Yubikey.

It functions completely offline and is used to derive the key. HAMC-SHA1 response is significantly more secure then any user memorable password. HMAC-SHA1 + user password creates a 2 factor encryption key and eliminates dictionary attacks. Malware would not be able to steal the HMAC-SHA1 response unless a) it caught the generation operation in flight (i.e. save KeePassX DB) or b) the Yubikey was plugged in and malware was able to access it (i.e. no hw button press required).

And the encryption key (via seed and challenge-response) changes every time, so if malware caught the derived encryption key only once, and the user saved the file again, the old key would no longer work. In a password only mechanism, the password caught once would be usable in the future.

@juju4
Copy link

juju4 commented Feb 7, 2016

+1
seems all issues where solve? can it be merged?

Thanks!

@skorokithakis
Copy link

+1 on this, any updates?

@Ardakilic
Copy link

+1, I'd love to have this feature implemented.

@sanyo-ok
Copy link

Hello,

I am in the process of evaluating different methods of securing my KeepAss password store.
OtpKeyProv is looking interesting, but I need to fully understand all dependencies
between keys and different conditions before using it with a real KP database.

My main concerns:

  1. To avoid being locked out from my own KP store
  2. To be sure it is secure enough,
    that at least other people cannot extract secret key from a stolen KP database,
    otherwise it is not useful to bother with all this typing these 3 pins everyday.

If I understand correctly verification of OTP is done on both sides (client and server)
by calculating following function:
HMAC(SecretKey,Counter)
So the SecretKey should be present on both client and server to allow client
to generate one time password and to allow server to verify if it is
a correct one time password received from a client.

Please help me to understand where secret key is stored?

After some reading I have found OtpKeyProv is somehow related to key file feature
of the KeepAss application. I guess may be a product of OTP HMAC calculation is used
to generate an analogue of temporary key file to unlock KP database?
But I do not understand where secret key is taken for calculation of HMAC by the plugin, especially taking into account secret shall be entered manually during recovery.

If the secret key is not present withing the KP database, then how HMAC(Key,Count) is calculated by the plugin?

But if the secret key is present in the database or in another place on the computer then it is not secure at all and the only another secure method is challenge-response with asymmetric keys?

@Canalytic
Copy link

Im using KeePassX 0.4.3 for Ubuntu Linux. I cannot find the challenge response settting for the master key, as per your first uploaded image.

@polyzen
Copy link

polyzen commented Jun 5, 2016

@Canalytic, this pull request wasn't merged. Afaik you have to use his fork for this feature.

@kerberizer
Copy link

kerberizer commented Jun 5, 2016

@Canalytic, also, this repo is for KeePassX 2.0. KeePassX 0.4 is the (rather) older previous version.

@Scoubi
Copy link

Scoubi commented Jul 8, 2016

Hi,

I manage to compile this fork on Mac OS X (El Capitan)

I'm unable to open my keepass db using my Yubiley. However, if I create a new DB with KeePassX with the challenge response it works.

I know my kdbx is good because I use it with Keepass2droid and Keepass on Windows.

Any idea on why it's not working and how I can fix it?
I used the latest libyubikey (1.13) and the latest ykpers (1.17.3) which are not the one refered to in this thread.
I also had to use qt5 and not qt4-mac

One thing I noticed, when I created my kdbx with keepass it also created a .xml file. When I created it with KeePassX it didn't.

I really want to be able to use my kdbx on my mac.

Thanks.

@denibertovic
Copy link

Is there still no comment from the maintainers on this? What needs to happen to get this merged and released?

@Nairwolf
Copy link

@denibertovic : Look when was the last commit of @debfx (the maintainer, I suppose), 25 May. I think he's really busy.

Also, a lot of others PR hasn't been merged yet...

I don't know if he accepts PR by the way.

@TheZ3ro
Copy link

TheZ3ro commented Sep 30, 2016

News?
This PR Need a Rebase

@sondr3
Copy link

sondr3 commented Oct 1, 2016

You could try to create this pull request over at https://github.com/keepassxreboot/keepassx

@ytisf
Copy link

ytisf commented Nov 24, 2016

Willing to support this feature with cash as well. Please update.

johseg pushed a commit to johseg/keepassxc that referenced this pull request Nov 28, 2016
johseg pushed a commit to johseg/keepassxc that referenced this pull request Nov 28, 2016
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
void setIcons(const QHash<Uuid, QImage>& icons, const QList<Uuid>& iconsOrder);
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the virtual keyword and the Q_DECL_OVERRIDE instead of C override ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question, I don't recall. Likely two minor bugs. I think you're the first person to review the code. Ever. :)

daniellandau pushed a commit to daniellandau/keepassx that referenced this pull request Feb 9, 2017
@sami10007
Copy link

I requested a review about your code from YubiKey support team. They say

We do not support [KeePassX]. We do know that they have already added support for CR several years ago. As to supporting the developer in getting this working, if they reach out to us we are more than happy to work with them on this.

Please, contact Aaron of the support team for troubleshooting the case further. It would be nice to get some reviews about the condition of the ticket.

@TheZ3ro
Copy link

TheZ3ro commented Mar 10, 2017

@sami10007 this feature has been merged in KeePassXC (the community fork of KeePassX) here: keepassxreboot/keepassxc#127, we talked with @a-dma in the PR and we will be happy to discuss further

@kylemanna
Copy link
Author

Thanks @TheZ3ro and others on the KeePassXC team for giving this a new home. Closing issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.