Keepassxc: GPG encrypted keyfiles

Created on 21 Nov 2017  路  11Comments  路  Source: keepassxreboot/keepassxc

What do you think about having the possibility of storing GPG-encrypted keyfiles and have KeepassXC decrypt them on-the-fly when their content is required? This would allow users who store GPG keys on a physical device (OpenPGP Card) to add an extra layer of security in a fairly transparent way.
This behavior can be emulated with the CLI once the --key-file argument code lands, but it would still be a bit of a hack.

An alternative could also be to have to possibility of specifying a script or a command to execute in order to produce the content of the keyfile, although this would have quite a few more security implications because of possible side-effects.

Thanks.

new feature

Most helpful comment

I don't really like executing scripts from KeePassXC, and a keyfile isn't really a safe user-provided field (unlike field inside the KDBX, where the user explicitly added it)

We thought about this and I think the choice was to implement a challenge-response against the PGP/GPG agent. This way we can refresh the secret part stored in the KDBX and perform a new C-R every time, a kind of "forward-secrecy" (like we do actually with the yubikey).

This method is a lot safer than plain gpg-encrypted keyfile (that are forever static so no "forward-secrecy" provided) but less "portable"

All 11 comments

I managed to get this to work, but it's very hacky. Now that --key-file works it is possible to use a gpg-encrypted keyfile. Unfortunately the code reading the keyfile content seeks the file. This means that tricks like <() in bash won't work. On zsh =() should work since it uses a temp file, but I haven't tested it.

The workaround I found to get this to work in bash is to use a here string. An example command for listing the credentials is

(gpg -d key_file.dat.gpg 2>/dev/null >/dev/fd/999; keepassxc-cli ls -k /dev/fd/999 Passwords.kdbx) 999<<<''

Any chance to change the code that reads the keyfile to something that treats it as a stream and buffers it internally? That would make process substitution (and possibly even pipes) work.

Any chance to change the code that reads the keyfile to something that treats it as a stream and buffers it internally? That would make process substitution (and possibly even pipes) work.

Honestly I don't see much usage other than this specific case.
Having a keyfile as file is the standard and so we shall read from a file, at least for core. Maybe cli can implement this

I agree that having a keyfile as a file is fairly standard, but since keyfiles are typically small in the grand scheme of things, maybe it would be possible to buffer them internally until the database is unlocked.

However, if you do not want to do this, I understand.

I just noticed that some people already asked about it in #255 and it was a "planned" feature.

I won't close this since it's more specific. I think I need to buy an OpenPGP key now.
Some help in testing/developing would be appreciated.

I've been thinking a bit more about this and came to the conclusion that having a more generic system to produce the content of the keyfile would allow a lot of flexibility.
If the keyfile is actually a script that can be run (what interpreter/command is used to do that could be a setting) we could do all sort of things. For example:

  • gpg decrypt a file
  • cat a file stored inside a LUKS/dm_crypt volume including fancier things like tomb
  • cat a file on a remote machine using ssh
  • use steganography
  • ...

Would you guys be in favor of something like this? What are your thoughts?

I don't really like executing scripts from KeePassXC, and a keyfile isn't really a safe user-provided field (unlike field inside the KDBX, where the user explicitly added it)

We thought about this and I think the choice was to implement a challenge-response against the PGP/GPG agent. This way we can refresh the secret part stored in the KDBX and perform a new C-R every time, a kind of "forward-secrecy" (like we do actually with the yubikey).

This method is a lot safer than plain gpg-encrypted keyfile (that are forever static so no "forward-secrecy" provided) but less "portable"

I see your point. However, it could still be a user-settable parameter whether to allow this or not.
As far as forward-secrecy goes, I don't see keyfiles as being meant to be changed often, but people who care about that can still do it (even today) manually or rely on the YubiKey mechanism. This wouldn't change that.

All in all I still think that is a very good opt-in feature that gives KeePassXC a lot of potential to integrate with many other applications, without having to explicitly write support for it.

Just my two cents.

I just wanted to update this to say that my earlier solution has stopped working a few updates ago (haven't tried to find out why), but using a named FIFO works. In case somebody find it interesting, this is how to use a gpg-encrypted keyfile.

(fifo=$(mktemp -u); gpg -d /home/user/key.file.gpg 2>/dev/null >$fifo; $(keepassxc --keyfile $fifo --pw-stdin /home/user/databse.kdbx); rm $fifo)

The main downside now is that the FIFO will be unlinked but not deleted until after KeepassXC exits.

As a side note, I still believe that having first-class support for gpg-encrypted keyfiles would be quite cool.

Pretty sure we're not gonna do that. If we are going to implement PGP, then it won't be via keyfiles, although I am still hoping for PGP to finally die, so it can make way for something else that can actually provide practical and secure message encryption.

I just wanted to update this to say that my earlier solution has stopped working a few updates ago (haven't tried to find out why), but using a named FIFO works. In case somebody find it interesting, this is how to use a gpg-encrypted keyfile.

(fifo=$(mktemp -u); gpg -d /home/user/key.file.gpg 2>/dev/null >$fifo; $(keepassxc --keyfile $fifo --pw-stdin /home/user/databse.kdbx); rm $fifo)

The main downside now is that the FIFO will be unlinked but not deleted until after KeepassXC exits.

As a side note, I still believe that having first-class support for gpg-encrypted keyfiles would be quite cool.

Would you care to explain how you made it work with a named pipe? The solution you offer above is not a pipe. You simply decrypt your keyfile into a temporary file, then delete it. There's no pipe or FIFO here.

Unfortunately it doesn't work with a FIFO. I used to have a call to mkfifo between the first two commands but it doesn't work (probably never has), because of how the keyFile is handled in FileKey.cpp where there are calls to make sure that it is a regular file.

For that reason I went back to a regular file that I manually delete after starting KeepassXC. Not the best solution but better than having the key file sitting unencrypted on the disk.

Relaxing some of the constraints on the type of file that can be used would help with this, but I understand that it opens up for a few tricky-to-reason-about issues and that the developers of this project may not want that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rugk picture rugk  路  3Comments

Throne3d picture Throne3d  路  3Comments

JosephHatfield picture JosephHatfield  路  3Comments

MisterY picture MisterY  路  3Comments

lostfictions picture lostfictions  路  3Comments