KeepassXC: HMAC mismatch when saving KeepassXC database after OnlyKey timeout (kinda SOLVED)

It happened again: “HMAC mismatch” when unlocking KeepassXC database with my OnlyKey as hardware key.

Update: Please see my latest post below for the probable issue (saving KeepassXC database after inactivity timeout of OnlyKey seems to alter the HMAC authentication).

New topic as I’m sure that I didn’t change ANYTHING with my OnlyKey. Two hours ago I could easily unlock my KeepassXC database, now I get the dreaded “HMAC mismatch”. All I did was adding some new passwords to my KeepassXC database, which lives in a Cryptomator container, so totally normal usage.

I’m not sure where the problem lies – with OnlyKey, or KeepassXC. I re-wrote the HMAC key to the OnlyKey, and also used my backup key (which has the same HMAC key), to no avail.

I can’t be the only one with this issue – is this problem well-known and addressed anywhere?

Again, my setup is:

  • KeepassXC database stored within Cryptomator containes, which resides on Dropbox.
  • KeepassXC database secured with OnlyKey as hardware key.
  • Latest versions of KeepassXC and OnlyKey.

Edit: See update below – I got it to work, but only if the OnlyKey is not unlocked. Before it worked when the OnlyKey was unlocked. What gives?

This is really strange – I’ve tried many more times, unplugging and reinserting the OnlyKey (without entering the primary PIN). Sometimes the unlocking works, sometimes it doesn’t, but only if the OnlyKey is not unlocked with the primary key.

I am positive that before the unlocking of my KeepassXC database worked when the OnlyKey was unlocked.

What could be the issue here?

For instance, what happens if the OnlyKey is unlocked first, but then locks due to inactivity timeout, and then I save the KeepassXC database when the OnlyKey is locked?

I did an experiment, and this actually confirmed my hunch, so I suspect that this is indeed the problem.

Experiment:

  1. Successfully unlock KeepassXC database with unlocked OnlyKey as hardware key.
  2. Wait until OnlyKey times out due to inactivity. (I set inactivity timeout to one minute.)
  3. Make a minor modification to KeepassXC database (so that it’s possible to save it) and save it. → I don’t understand exactly why, but saving the KeepassXC database while the OnlyKey is unlocked seems to alter the HMAC authentication. KeepassXC doesn’t give any warning.
  4. Unplug OnlyKey and reinsert it, then unlock it.
  5. Try to unlock the KeepassXC database with the unlocked OnlyKey as hardware key → this should fail due to “HMAC mismatch” as reported above.
  6. Unplug OnlyKey and reinsert it, then do not unlock it.
  7. Try to unlock the KeepassXC database with the locked OnlyKey as hardware key → this will work.

So my question is: Is this expected behavior (and can you please explain why)? I am not a crypto expert, but to me it seems that it shouldn’t happen, and that KeepassXC should not save the file (and thus somehow alter the HMAC authentication) if the hardware key is locked (i.e., in a different state).

I suspect that many people fall into this trap, so in any case it would be very useful if there would be a warning somewhere, in both the OnlyKey documentation, but also with KeepassXC.

What do you think?

Sorry to hear you are having this issue.

I can’t be the only one with this issue – is this problem well-known and addressed anywhere

I monitor issues from other users and have seen lots of KeepassXC questions but no other users reporting this mismatch issue. By default no setup is needed to use HMAC challenge-response, a random key is used and HMAC button press is required. I think the combination of custom settings here is why you are seeing the issue and it hasn’t been reported previously.

I re-wrote the HMAC key to the OnlyKey, and also used my backup key (which has the same HMAC key)

Yes you can set a custom HMAC key if you prefer to not use the default. You should probably not however set your HMAC key as your backup key. Your backup key/passphrase is just a key that is used to encrypt your backups and is unrelated to challenge-response.

Thanks for the detailed write up, I suspect why you are running into this issue and not other users is that you have set a custom key and you have disabled the default “Button press required”. When OnlyKey locks/timeout it essentially reboots. While locked, the key provided HMAC response is not using your custom key (as that and all other data is encrypted while OnlyKey is locked) instead its using essentially random data as your HMAC key, so you are getting an HMAC response that doesn’t match.

So not a security issue but definitely a usability/availability issue. As you found, a user that runs into this issue would know the next time they try to unlock. We are testing the next firmware release now so I will make sure this issue does not occur in next release. In the meantime one work around would be using the default button press required for HMAC.

Thanks t11 for the detailed response. I’m looking forward to a better handling on both OnlyKey and KeepassXC sides. Happy to test any changes. (Wouldn’t it be best if OnlyKey would not repond to HMAC challenges when locked?)

On the KeepassXC side, would it not be possible for KeepassXC to detect that the HMAC key has changed (from the one used to unlock the KeepassXC database), and in this case avoid saving and thus altering the HMAC authentication?

Also, could you please elaborate a little bit more for my understanding:

Is this “essentially random data as your HMAC key” fixed for a given key? For instance, if I reboot the key several times (by unplugging and reinserting it), would the HMAC key that’s used when the OnlyKey is locked be the same? What determines it (happy to read some C/C++ code to get a better understanding)?

I guess the “HMAC key” can’t be queried for security reasons, but is it possible to get an HMAC response through the Python CLI or similar?

Finally, a clarification on my side:

I was imprecise with my terminology here. By “backup key” I didn’t mean the cryptographic key used for OnlyKey backups, but a secondary hardware OnlyKey which serves as clone (backup) of my primary one. In other words, I configured both OnlyKeys (primary and secondary / backup) with the same HMAC key in HMAC slot 1, so that I can use both interchangeably. Sorry for the confusion.

On the KeepassXC side, would it not be possible for KeepassXC to detect that the HMAC key has changed (from the one used to unlock the KeepassXC database), and in this case avoid saving and thus altering the HMAC authentication?

No, an HMAC response is 20 hex bytes. It changes every time based on input and there is no way to know what key was used to generate it. You can’t for example take that 20 bytes and figure out what the private key was, if you could HMAC would not be very useful at all. You can imagine on devices that require no PIN like Yubikey if you could do that it would not be very useful for 2FA.

I guess the “HMAC key” can’t be queried for security reasons, but is it possible to get an HMAC response through the Python CLI or similar?

You could probably build something, there is nothing currently that does this.

Is this “essentially random data as your HMAC key” fixed for a given key?

I think you might mean given input. Every time you request an HMAC the app (KeepassXC) sends a random challenge, that challenge is HMACed with a private key, the response is the HMAC. Given the same key and same challenge the response is the same. Your KeepassXC database saves the challenge it sent last time, sends that again and if the private is the same the response can be used as part of the key to decrypt your database (the other part being password).

I think this part I understand. However, given what you wrote, it’s possible for KeepassXC to infer whether the HMAC private key has changed before saving, by sending the same HMAC challenge again that was used to unlock the KeepassXC database initially. And you seem to suggest that KeepassXC actually does this already, which is what I meant with my suggestion (see bottom of this message):

  1. KeepassXC sends HMAC challenge to hardware key, and remembers the challenge.
  2. Hardware key computes HMAC response as function of HMAC challenge and HMAC private key. KeepassXC remembers the HMAC response.
  3. When saving, KeepassXC, sends same HMAC challenge as in step 1 to hardware key. If it returns the same HMAC response, then the HMAC key didn’t change. Otherwise it should give a warning and not save the database.

No, I meant hardware key / OnlyKey (imprecise lingo again, sorry). In other words, how likely is it that the HMAC private keys are the same for two different locked OnlyKeys?

And wouldn’t it be better if OnlyKey rejected HMAC challenges when it is locked?

If this is already happening, and KeepassXC tries to detect whether the HMAC private key of the hardware key has changed to when it was unlocked, then I don’t understand why my issue exists. It seems that KeepassXC could avoid the issue by refusing to save the database when the HMAC private key is inferred to have changed compared to the HMAC private key that was used to unlock the database.

  1. When saving, KeepassXC, sends same HMAC challenge as in step 1 to hardware key. If it returns the same HMAC response, then the HMAC key didn’t change. Otherwise it should give a warning and not save.

KeepassXC stores the challenge, it doesn’t store the response. So it has no way of knowing if the response is correct except that decryption of a database is successful.

And wouldn’t it be better if OnlyKey rejected HMAC challenges when it is locked?

Yes, as identified here there is clearly a use case where it causes a usability issue.