title: "Roll your own linux password manager w/ gpg and openssl" date: 2019-01-16
Managing your passwords is important, and can be difficult to do well. This post details how you can quickly and easily write a personal password manager to use strong, unique passwords on all the many sites and services you may use online.
First, a bit of context about why I think a system like this is important. The primary reason to use a password manager, in my opinion, is because of the regularity and severity of data breaches; see here and here for stories about the growing prevalence of this problem.
We provide websites and web services, often many, many different sites and services, with large amounts of data and personal information, and sometimes the entities/companies holding that information lose control of it. They get hacked, or there is a bad actor within the company, or something else happens that that information gets leaked. For some services, especially those with a lot of personal information in their databases, a single breach can be very damaging to a person.
But the kicker is that if you reuse the same password on multiple sites, you risk letting that single data breach be much, much more damaging than it has to be. Once a malicious actor has your password for your email account, they are likely to try the same password, and variants of it, to log into whatever other accounts they can tie to you: social media accounts, banking accounts, web forums, university services, professional or corporate web portals, healthcare websites, etc. This is called credential stuffing. Because of this risk, password re-use is bad practice, and you should avoid it if you can.
One last note: some people use "unique" passwords for different sites, but use a common stem with a unique tail. For example, say you are signed up to 3 different web services, you may create passwords that look like this:
This will offer a little more protection than having identical passwords for each site (the password hashes won't be the same, and an attacker may have difficulty guessing the tail of the passwords for other sites), but it is not as secure as having unrelated, unique passwords. Fortunately, with the system below, we'll see how easy it is to create such passwords.
So if I've convinced you of the value of password management, or if you came here so convinced already, read on!
The following password management system will not work for everyone. It is specifically tailored to someone who uses a single device (i.e., a laptop) for almost all of their computing, who runs GNU/Linux, and who spends a lot of time within a shell/terminal emulator. This is, of course, a fairly small niche. The ideas can be adapted to other setups (e.g., laptop + desktop + smartphone), but you will have to do some more legwork to get it working. If you'd like some help doing so, feel free to email me.
There are three parts to the password manager:
Let's break down each part.
First we create a plain text file with our passwords in it. We will assume, for the sake of this tutorial, that the file will be called password_file, but I would encourage you to use something a little less likely to draw unwanted attention, in the unfortunate event that someone gets hold of your machine that you'd rather hadn't.
Open up your text editor of choice, and enter your passwords, one per line, in the following format:
service:password
The name of the service can be whatever you like; it's what you will use to query the password file later, so don't make it too long.
Enter all the passwords you'd like to manage. At the end of this step, you should have a file that looks like this:
webService1:coolpassword1
fastmail:coolpassword2
uniMail:awesomepassword
socialMediaSite:lamepassword
At this point, you have two choices: you can encrypt this file, and move on to writing the shell script and the shell alias that will allow you to decrypt and query the file. Or you can generate new, strong passwords for each of the services listed, and go change those passwords through the services' respective interfaces (e.g., login, go to account/preferences/settings, and choose change password). I would strongly encourage you to do this. Maybe not right away; you could change the passwords for the various services incrementally, over time, and achieve the same effect. Changing your existing passwords to stronger ones will likely be the most time consuming portion of this process, but it's also the most valuable.
To generate a password, simply open a terminal and run this command:
$ openssl rand -base64 24
Caveat: sometimes this command will generate a password with a character in it that won't be accepted by the website/service for which you're trying to change your password. In that case, just generate another one. They are cheap to create, after all.
This command will generate a psuedo-random, 24 character password (you can use whatever length you'd like). It will not be the sort of password that you can easily memorize, but your encrypted file will have no trouble with it. These passwords will be much harder to crack than most of the passwords people generate out of their own head. And a fringe benefit of using these passwords is that you can clear the space in your brain memory that was previously allocated to password storage of all these sites, and put more interesting data in it, such as the names of all the world's national capitals.
Once you've got your password file in place, hopefully with a bunch of new, strong, gibberish-looking passwords, we move on to encrypting the file.
To encrypt the text file, quit your text editor, open a shell/terminal, and type the following command:
$ gpg -c password_file
or, if you are not in the same directory as the password file, you can type:
$ gpg -c /path/to/password_file
GPG will then prompt you for a password, which will be used to perform symmetric-key encryption. This password you will have to remember, because you will be typing it in whenever you query your encrypted file for a website password. Make sure to choose a strong password, but one that you can remember (or write it down on a piece of paper while you're learning it). I recommend rotating this encryption password regularly.
You should now have an encrypted password file, called password_file.gpg. You can decrypt the file with the following command:
$ gpg -d password_file.gpg > password_file
GPG will prompt you for your encryption key/password, and upon entering it you will again have the plaintext file. Whenever you need to add a new website/service to this file, you will decrypt the file, add a new line, re-encrypt it, and finally delete the plaintext version. You will follow the same procedure if you change the password for an existing service.
Now that your password file is setup, filled with strong passwords, and encrypted, we need a way to query it. We can do that with a simple shell script that uses gpg, grep, cut, tr, and xclip. All but xclip are usually installed by default on GNU/Linux distros, and all are readily available in the repos for most any distro. You should have no trouble tracking down these utilities.
The logic of the shell script is very simple:
The entire script file looks like this:
#!/bin/sh
gpg -d /path/to/password_file.gpg > /path/to/decrypted/password_file
grep $1 /path/to/decrypted/password_file | cut -d ":" -f 2 | tr -d '\n' | xclip
rm /path/to/decrypted/password_file
echo RELOADAGENT | gpg-connect-agent
This will look for the colon after the service name you feed into it (via the shell alias, up next), cut the line there, and return just the password. It then feeds that result into xclip, which simply puts the text into your X clipboard. You can then middle-click or shift-insert to paste the text into, e.g., a browser login window, and the password text never needs to be visible on screen, and therefore remains safe from visual capture via, e.g., shoulder surfing.
You can call this script file anything you like. I call mine pman.sh, in keeping with the Unix tradition of very short program names. You will use the filename in your shell alias definition below.
Finally, you can make use of this shell script easier by defining a shell alias in your .bashrc or .zshrc (or whatever other shell you may be using).
The alias definition that I use, for use with zsh, but which should work the same in .bashrc, is the following:
$ alias pw="/path/to/pman.sh "
Note the space after the file name/extension. This is important, otherwise the filename will run-on to the argument.
This line defines the alias pw. So to grab my email password, I type
$ pw email
get prompted by gpg for my password (i.e., encryption key), and that's it. My password is now sitting in the X clipboard, ready to be pasted into either a terminal (I use this all the time with the mail user agent (MUA) program that I use, called neomutt) or a browser window.
Put the alias line into your shell's rc file, and then source the file, e.g.,
$ source ~/.zshrc
or open a new terminal, and try out your new tool. You should now have a fully-functioning (if alpha-level) password manager!
In overview and summary, the steps to build your own password manager are:
Hopefully this tutorial will help some privacy and security enthusiasts and/or some GNU/Linux and free software supporters manage their passwords a bit more securely and comfortably. If you have any feedback, suggestions, or questions, feel free to email me.
As a final note, if you use multiple devices, or for some other reason don't want to use the system I've detailed here, I encourage you to look into some of the commercial password managers out there that do this sort of thing. These tend to install as browser add-ons/plugins, rather than being run through the terminal or via a desktop app. Some of the best on the market include LastPass and 1Pass. Commercial password managers are even easier to use than the system I've described here, and they will provide an important layer of security to your online activities.
Happy surfing!