ktyl ~ blog

Decentralised password management

Password managers are a fact of modern life. Popular examples include KeePassXC, 1Password and the one I've personally used for years, Bitwarden. They have slightly different sets of features, are varying levels of open-source, but all generally work well and provide cross-platform access to a password vault protected by various kinds of authentication.

Bitwarden works well, but its Linux support leaves a lot to be desired. The clients available on Arch bitwarden and bitwarden-cli are slow to start up as they attempt to sync the vault, and are awkward to navigate as a power user. bitwarden is a graphical application with some keyboard shortcuts, but is too complicated for efficient use. bitwarden-cli has performance issues, and requires external scripting to be able to copy things to the clipboard. Both applications depend on several hundred megabytes of dependencies, which is needless for something which ultimately manages a dictionary of strings and does a little cryptography.

I've also made substantial use of Bitwarden's browser plugins for Firefox and Brave, but there unsurprisingly exists none for my current browser of choice, qutebrowser. I prefer the light and minimal approach to web browsing qutebrowser engenders, so I'd rather find an alternative password management workflow than have my hand forced by what extensions are available.

Lastly, an issue with all mentioned password managers is their dependence on a particular cloud host. Though it is easy to export the vault, and therefore not really a point of failure, being dependent on a particular company paying their hosting bills ad infinitum will ultimately be a point of minor frustration. At some point, Bitwarden will fold and I'd have to change anyway!

So, I've decided to explore what it would take to avoid a minor frustration far in the future by undertaking a much more complex frustration, immediately, in the name of slightly improved resilience and independence, and a better fit to my needlessly esoteric usage requirements. Off we go!

The standard UNIX password manager

pass is a dead-simple password manager which stores passwords in files named after the thing they are for. It uses existing technology for authentication (GPG), clipboard access (xclip) and copying stored passwords between machines (Git). It is also very tiny - on my system the total installed size is 50 KiB.

Passwords can be generated and retrieved with:

# generate a password for example.com
pass generate example.com/ktyl

# retrieve the password and copy it to the clipboard
pass -c example.com/ktyl

GPG

Passwords are encrypted with a GPG key, a popular public-key encryption method used to validate updates in package repositories and validate identities of source contributors to those packages. GPG is also often used to encrypt email and other forms of communication in open-source communities.

GPG keys are very similar to SSH keys, but notably different in that they force the use of a password, while SSH keys may be passwordless. They also differ in that GPG keys aren't named, but rather are stored on a keyring. I will leave it for a future post or to someone else entirely to explain what a keyring is.

I first installed gnupg and created a GPG key using gpg --full-gen-key. I gave it my email address, set it to expire after a year and used otherwise default encrpytion options. The key has now been added to my public keyring, which I can verify with gpg --list-keys.

Importing keys

Since I've been using Bitwarden for years, I have hundreds of passwords saved. I don't want to have to copy them manually, either all at once or on a case-by-case basis (although that would rid me of all the defunct and unused passwords). Thankfully, a community extension pass to import passwords from other managers is available in the form of pass-import. With this tool, I was able to import my exported Bitwarden vault with a single command.

Inter-device access

A requirement of a password manager for most people is that it be available, whatever device they're using. To this end, pass uses Git, a near-ubiquitous collaboration and backup tool among software developers. This has the advantage if diversifying the available hosts for backing up passwords from the one cloud service provided by most password managers to anything which can host a Git repository. Popular Git hosts today include GitHub, GitLab, BitBucket and SourceHut. Many also choose to self-host collaboration tools such as Gitea or GitLab Community Edition.

Any of the aforementioned tools allow for the creation and management of Git repositories, but also come associated with substantial project management tooling, none of which is necessary for a password manager. In my case, I am using the most minimal possible setup, which is a Git server on my VPS - I wrote a blog post on setting this up here. With my setup, password access is disallowed - access is allowed only through the use of SSH keys.

I need access to my password manager on Linux, Windows and iOS. For maximum functionality, I'd also like a way to access it from a web browser, à la vault.bitwarden.com, but that brings in a whole bunch of security challenges, not to mention hosting. For now I'll content myself with copying a password manually from my phone occasionally, and maybe come up with something slicker in the future. Better safe than sorry!

For Windows I intend to use qtpass, a cross-platform GUI frontend for pass. I'll not bother documenting it here, because it's the weekend, and Windows is eternally a Monday problem. A more interesting challenge however, is iOS.

Pass for iOS

passforios is a pass client for iOS. The challenge in setting this up is finding ways to transfer not only the public and private GPG keys to the walled-garden iPhone, but also a private SSH key. The quickstart guide describes a few methods to do this, for which I opted to use the asc-key-to-qr-code-gif script. This avoids sending private keys over any network by converting keys to a QR code, which the iPhone can then scan.

I ran into some trouble when transferring a private SSH key, in that my Git remote refused the key with an error of callback returned unsupposrted credentials type. This GitHub issue detailed some specifics about acceptable key formats, and I ultimately ended up generating a working one with:

ssh-keygen -t rsa -b 2046 -m PEM -f passforios_rsa

This wasn't the end of my trouble, either. I found I had to present the URL in a weird way that I've not seen before, specifying the absolute path of the repository on the server, as opposed to relative to the git user's home directory.

# bad
ssh://git@domain.com:pass.git

# good
ssh://git@domain.com/home/git/pass.git

After that however, it worked! I could see the passwords I'd imported earlier from Bitwarden, and was able to add new ones. Success!

Final notes

Overall, there's a lot more setup involved for pass compared to a more orthodox password manager. For most people, I wouldn't recommend it - convenience is absolutely key for security practices, and this took me the better part of a day to set up, as a technically-inclined person. On iOS particularly, the app is functional, but I can appreciate it's less convenient than being able to use the built-in biometric security to unlock one's vault. I think the process is likely much easier with an Android phone. This is something I'm willing to put up with because of the improved experience on Linux, but is absolutely something to consider for those with other use cases.

If you have any questions, or if I've got something horribly, terribly wrong, I'd love to hear from you!