Skip to main content

Your own password store #1

Build the store

I’ve been using pass for years now. No cloud vault, no subscription, no company holding my passwords: just a folder of encrypted files in a git repository, which I can read with any tool I like. When the Android app I used to read that folder on my phone was archived, I forked it, and that’s how HardenedPass was born.

The thing is, every time I try to explain this setup to someone I see their eyes glaze over at the third acronym. GPG, SSH, git, remotes, keys… it sounds like a lot, and honestly the first time it is a bit of work. But you do it once, and it’s a lot less scary than it looks.

So I’ll take you by the hand and we’ll build a password store from scratch, starting from nothing, and by the end you’ll have your passwords on your phone, encrypted and synced. You don’t need to know anything about git or GPG, I’ll explain what you need as we go, and you can copy and paste every command.

This is a series in three parts. Today we create the store, in part two we give it a home on a server, and in part three we put it on your phone and start using it.

What are we building?

Three tools, each doing one job:

  • pass keeps every password in its own small file, and folders group them. That folder is called the store.
  • GPG (the program that does OpenPGP encryption) locks those files. You get a pair of keys: the public key locks, the private key unlocks, and a passphrase protects the private key.
  • git keeps track of the changes and copies the store between your devices, going through a remote, which is simply a copy of the repository living on a server.

Here’s the part that makes all of this work: the server only ever sees encrypted files. It can’t read your passwords, and neither can anybody who breaks into it. Decryption happens on your devices only, with a key that never goes to the server.

Diagram. On your devices, pass turns the password hunter2 into an entry called example.org, and GPG locks it into the encrypted file example.org.gpg. Git pushes and pulls that encrypted file to and from the server. The private key and passphrase unlock the files and stay on your devices. On the server the file name is visible, but its content is not.
What the server can see
Passwords and everything else inside an entry are encrypted, but file names are not. If you have an entry called bank/mybank.example.org, whoever can read the repository knows you have an account there, and git history tells them when you changed it. That’s why we’ll keep the repository private, even if the content is encrypted.

Computer or phone only?

You have two ways of doing this, and both end in the same place.

With a computer Phone only
Typing commands Real keyboard, copy and paste On a phone screen, in a terminal
Extra software pass, GPG and git, usually one command Termux, a terminal app for Android
Backup of your key Easy, on a USB stick You must find a way to get it off the phone
Using the store on a computer later Already there Needs the key moved over

HardenedPass can’t create OpenPGP keys, it only imports them, so something has to make the key for you. If you have access to a Linux computer, even for half an hour, take that road: it’s more comfortable, and backing up the key is much easier. It’s what I’ll describe first. If you only have your phone it’s perfectly doable, follow along anyway because I’ll explain everything here, and then jump to the phone only route in part two, which uses the same commands.

Install the tools

On Linux everything’s in your distribution’s repositories:

bash
1
2
3
4
5
6
7
8
# Debian, Ubuntu, Mint
sudo apt install gnupg pass git

# Fedora
sudo dnf install gnupg2 pass git

# Arch
sudo pacman -S gnupg pass git

On Slackware you already have GPG and git, and password-store is on SlackBuilds.org.

On macOS you can get the same tools from Homebrew with brew install gnupg pass git. On Windows pass doesn’t run natively, so install WSL with its default Ubuntu and use the Debian command above inside it. From here on, all the commands are the same.

Now tell git who you are. This is only a label on your changes, it doesn’t need to be your real name:

bash
1
2
git config --global user.name "Your Name"
git config --global user.email "you@example.org"

Create your key

bash
1
gpg --full-generate-key

GPG will ask you a few questions. Here’s what I’d answer:

  1. Kind of key: press Enter to accept the default. On a recent GPG that’s ECC (sign and encrypt).
  2. Elliptic curve: press Enter again, for Curve 25519.
  3. How long the key should be valid: press Enter for does not expire, then y to confirm.
  4. Real name and email address: they don’t have to be real, but remember the address, you’ll need it in a minute. Leave the comment empty and press O to confirm.
  5. Passphrase: this one deserves its own section, see below.

The defaults are good, but you have alternatives:

  • RSA (option 1) is the old reliable: bigger and slower keys, but it works everywhere. Pick it only if you have a reason to, for example an old tool that doesn’t understand the newer curves.
  • ECC and Kyber is the new post-quantum option in the latest GPG versions. Stay away from it for now: it’s very new and not everything can read it.
  • An expiry date, like 2y, is a safety net: a key you lost stops being valid by itself. The price is that you must remember to extend it, so if this is your first key I’d rather keep it simple and not set one.

Choosing a passphrase

The passphrase is the last line of defence: if somebody gets a copy of your private key, this is the only thing between them and all of your passwords, and they can try guessing it on their own machine as fast as they like. So it has to be strong, but you also have to remember it and type it, because nobody can recover it for you. There’s no “forgot my password” link here.

There are two ways of making a strong one:

Random characters Diceware
Looks like q7#Vm2!xTz9&Lp4w smartness-dayroom-celtic-cheer-anointer-pulley
Strength 16 characters: about 105 bits 6 words: about 77 bits, 7 words: about 90 bits
Easy to remember No Yes, after a few days
Easy to type on a phone Painful Quite easy
Good for What a password manager remembers for you What you have to remember

Diceware means picking random words from a list of 7776, traditionally by rolling five dice for each word. The trick is that the words must be picked at random: a sentence you came up with yourself, or your favourite song lyric, is much weaker than it looks, because people are terrible at being random. Each word adds about 12.9 bits, which is why length matters more than the words themselves.

Random characters pack more strength in less space, but you’ll never remember them. So my advice is: 7 diceware words for your GPG passphrase, the one thing you need to memorize, and let the app generate everything else. The EFF wordlist and instructions are all you need, plus real dice if you have them. Write the passphrase on paper while you learn it, and keep the paper somewhere safe at home.

When you’re done, GPG prints a summary with a line looking like this:

1
2
3
4
pub   ed25519 2026-11-06 [SC]
      1905811B654B494FBD151671593A16E792BC639D
uid                      Your Name <you@example.org>
sub   cv25519 2026-11-06 [E]

That long string is your key’s fingerprint. GPG also made you a revocation certificate, a file in ~/.gnupg/openpgp-revocs.d/ which tells the world the key shouldn’t be used anymore, in case you lose control of it.

Back up your key, now

If you lose your private key, your passwords are gone forever. There’s no way around this: it’s the same encryption that protects you from everyone else. So let’s do this before we put anything important in the store.

bash
1
gpg --armor --export-secret-keys you@example.org > private-key.asc

GPG asks for the passphrase and writes your private key in private-key.asc. Copy that file and the revocation certificate on a USB stick that stays at home, preferably an encrypted one, and keep the file around for now, because the phone will need it in part three.

Create the store

Use the address you gave to your key:

bash
1
2
pass init you@example.org
pass git init

The first command creates the store in ~/.password-store, and the second turns it into a git repository. From now on pass saves every change in git by itself.

Let’s add a first entry, to have something to test with. The first line is always the password, anything below it is extra information. Type this and finish with Ctrl+D:

bash
1
pass insert -m example.org
1
2
3
hunter2
username: alice
url: https://example.org

Check that it works with pass show example.org: GPG asks for your passphrase and you should see those three lines.

Up next

If you made it up to here, you have a working password store, but for now it only lives on this computer. In part two we’ll choose where to keep a copy of it, and I’ll go through the options, from the big hosted services to your own server.

See you on the next one 👋