Text-Based Password Manager

Using the pass command line as a text-based password manager

Everyone needs a password manager. I have dozens of credentials to several websites. Re-using password across websites is no. Memorizing dozens of different password is also a no. The only way is to use a password manager.

For so long, I’ve been searching for the simplest possible password manager. I only need two criteria: plaintext and git-friendly.

Why Plaintext?

Yeah, you heard that right, it has to be plaintext. But that doesn’t mean it has to be stored as real plain text, where everyone or every machine can read it. That would be so wrong. What I mean is it has to be stored as simple text files, not binary. If you ever see the content of your public and private ssh keys, that’s what I mean.

Why git-friendly?

I’ve been using git for my every digital activity, not just programming. I store my blog content in the git repository. I write documentation in the git repository. Now I also want to store my password in the git repository. By using it, I can do auditing on my own. Also, it would be easy to sync between devices by using a git repository. And I don’t need to depend on certain cloud services to sync my passwords. I can use any computer or services with a private git repository.

This is where I found pass.

pass is a simple, yet efficient password manager. It’s actually a shell script utilizing gpg and git under the hood. You can read more about it on their documentation. Let’s get started.

First, we need to install the software. Use your favorite package manager. Since I’m using macOS, so I use brew. What we need in our system are gpg, git, and pass.

$ brew install gpg git pass

Next, we need to generate our gpg key, if you don’t have one. Simply type the following command.

$ gpg --full-gen-key
gpg (GnuPG) 2.2.15; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Select RSA and RSA as the key kind.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1

The rule of thumb of key size is, the bigger it is the better. Bigger key size meaning longer time to encrypt or decrypt. But, using today technology, that won’t be a problem. 2048 should be enough, but you can choose 4096 for future-proof.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits

Set the key so it won’t expire.

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

Enter your full name and your main email. Remember your email because it’s be used as your gpg ID.

GnuPG needs to construct a user ID to identify your key.

Real name: John Doe
Email address: johndoe@example.com
Comment:
You selected this USER-ID:
    "John Doe <johndoe@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

You’ll be asked for a password. Think of it as master password and memorize it. You’ll need this to decrypt your stored passwords. Follow the rest of the instruction and wait until the process finished.

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 841EC76A047727DE marked as ultimately trusted
gpg: revocation certificate stored as '/Users/johndoe/.gnupg/openpgp-revocs.d/498EDEFDCDACED211B20561F841EC76A047727DE.rev'
public and secret key created and signed.

pub   rsa4096 2019-04-16 [SC]
      498EDEFDCDACED211B20561F841EC76A047727DE
uid                      John Doe <johndoe@example.com>
sub   rsa4096 2019-04-16 [E]

Now let’s init your pass directory. Use your previously created gpg email as ID.

$ pass init johndoe@example.com
Password store initialized for johndoe@example.com

Since we’re going to sync it through git repository, we also need to init the git repository.

$ pass git init
Initialized empty Git repository in /Users/johndoe/.password-store/.git/
[master (root-commit) 682f5cd] Add current contents of password store.
 1 file changed, 1 insertion(+)
 create mode 100644 .gpg-id
[master 57a34f5] Configure git repository for gpg file diff.
 1 file changed, 1 insertion(+)
 create mode 100644 .gitattributes

You need to create a git repository server. You can use private repository on GitHub, BitBucket, or GitLab. Or better yet, you can create it on your own server. After that, add it as a remote origin.

$ pass git remote add origin git@github.com:username/.password-store.git

Obviously, don’t forget to change username with your own username when you copy the command above.

Push the content of your password store to your git server for the first time.

$ pass git push -u --all
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 532 bytes | 266.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:username/.password-store.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

Now before we add anything to our password store, we need to set an environment variable. As you may recall earlier I want the password stored as text files. By default, pass will store it as a binary file with .gpg extension. We can actually change the output as ASCII-Armor. To do that, open ~/.bashrc or ~/.bash_profile to set this environment variable.

export PASSWORD_STORE_GPG_OPTS=--armor

Close and re-open your terminal so the environment variable is set.

Next, we can use the password store to generate random passwords. For example, let’s create a random password for reddit.

$ pass generate reddit.com 10
[master 8db44d6] Add generated password for reddit.com.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 reddit.com.gpg
The generated password for reddit.com is:
Tu%s0*!9$]

To get the stored password, type following command. You’ll be asked for your gpg password. Remember to memorize your master password from the earlier step.

$ pass reddit.com
Tu%s0*!9$]

You can also store it in your clipboard instead of print it on stdout.

$ pass -c reddit.com

If you want to see how pass stores your password, the encrypted content looks like this:

$ cat ~/.password-store/reddit.com.gpg
-----BEGIN PGP MESSAGE-----

hQIMAxUJw39tQpWhAQ//Uydwf0p/WwtND0fmV2wRLM7GlFFzd/DxdhgyRjg3Cuuc
VOxlCZrTbQv5JOKVs+UcMoyhEYr3Get+Ki7FbyRtRLl3MECjjU44N98v83E/ozfo
V6i2Fn+DtH5oYnavIQ+7eQfH0mGhLU+FhZSOou3uGfSMfBntxDqJZsPiWtFVcSHj
cXnxyrzlPlp+jTYziYvn3vprQoheg9nEvxm/etPgAm0+pQNqAk2izoh0L/hQBu+F
gB954GxxJpIzLi2dZFNJsK3CZRTdjI++Sw62dZc3ulmeqCh0VOyBAB1hmxO/Rrvs
rSO+lKjoOmqpdGam5aQ24arA8fD3ss3Ztby2KmtwuIccM/KdePoPxONDxoVhPMDa
nGe/HcF/M6eGqIco5TLdCedaDYiI8ZbNSf8oSYjsHwl3cZJCV2cF9++PYKryLwNO
YkKaS7OAY/ZBGu9tBxLmaSFNiFQbC7zn/6K57S16RkQ+IF2dOTDqZh8XeM0z9Qoi
ra6P7gkZBtP8jEuQJmYVboq+JMTVxmEYH620E3btxh3gdwI6SJ0Je972/oBEqtBD
zJ/19gt4Fh/l67waQpaFWgdSjEhlzbZktd70I18zOZaUQ4lQLMdWc3aZdH1t6uSi
lICx/qbY8a7tPRqS4KBNQqNgS2Ffugy3kAM1zrAIaY21jD6fUOg2HZ4IocmM8SPS
PAHe23XnxcbVlmPCRgtoe8n4mZfbdbidU6seXtQNr14jbjm4mnYE4I6HXvO5PaBm
5Cr5Rp4gxY/vpVWSHw==
=7AGH
-----END PGP MESSAGE-----

Finally, you can push your passwords using git.

$ pass git push
Enumerating objects: 29, done.
Counting objects: 100% (29/29), done.
Delta compression using up to 4 threads
Compressing objects: 100% (28/28), done.
Writing objects: 100% (28/28), 7.50 KiB | 960.00 KiB/s, done.
Total 28 (delta 8), reused 0 (delta 0)
remote: Resolving deltas: 100% (8/8), done.
To github.com:username/.password-store.git
   57a34f5..88af558  master -> master

So that’s it. In the next tutorial, I’ll write about how to sync it to other devices like your iPhone and iPad.

References

Cover Photo by Kevin Horvat on Unsplash.