This software is no longer actively developed or maintained. I have switched to using the (confusingly similar-named) tool from https://www.passwordstore.org/. The general ideas are substantially similar, the main differences being:
-
this tool uses a single file versus one per item, which obscures some metadata at the cost of less flexibility (e.g., you cannot use this
pass
to share subsets of your repository with another gpg key) -
the zx2c4
pass
actually has an active community with up-to-date ecosystem tools, like https://github.com/passff/passff
So while I don't know of any particular problems with this software, I overall recommend not using it in favor of the zx2c4 tool.
Pass
makes it easy to store passwords (or any other secret data). It
aims to be secure and easy to integrate with existing Unix tools and
version control. The encryption is all done by gpg, using one (or more)
keypairs, and the contents themselves are organized as YAML. A vim
plugin is provided to make editing the encrypted file easier.
Here's an example. The file is encrypted on disk with gpg:
$ cat ~/.pass/pass.gpg
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.15 (GNU/Linux)
hQQOAwC+u3g6GPWoEBAAtdHigCS83FWokK9fFAwjVNx1nhdVCWlReKgIftktoUKj
ZjKzBk9gLmUHi0UMVjAtbxkhscEzLtVyBhlhpIMbG2/iEjoxS90ZnBWhavJWGQtd
[...]
UC6q6YCaR9qcfhVHAvcBIuCq1u3GwsZd0NyY+buJj38APc1JZshugCWu
=/oK0
-----END PGP MESSAGE-----
The decrypted contents are YAML:
$ gpg -qd <~/.pass/pass.gpg
# recipient: me@example.com
mybank:
desc: MyBank Savings and Loan
username: me
password: foo
Note that we didn't enter a passphrase above; this system works much
better if you use gpg-agent
, which will prompt for and cache your
password outside of the terminal.
Using the vim plugin, you can edit it just like a regular file. The decrypted contents are never stored on disk, and you can commit the result. The version control system will see only the encrypted version, so you are free to push it. A git diff-helper makes diffs more readable.
Updating an entry might look like this (the editing happens inside vim, with the decryption/encryption steps transparent to the user):
$ vi ~/.pass/pass.gpg
$ git diff
diff --git a/pass.gpg b/pass.gpg
index f42955f..b42cffe 100644
--- a/pass.gpg
+++ b/pass.gpg
@@ -2,4 +2,4 @@
mybank:
desc: MyBank Savings and Loan
username: me
- password: foo
+ password: bar
You can query a whole subtree of data:
$ pass mybank
mybank.desc MyBank Savings and Loan
mybank.username me
mybank.password bar
or a specific item:
$ pass mybank.pass
mybank.password bar
Note that we don't need to use the full item name. The keys are
substring regexes, and can match either item names, or their desc
fields:
$ pass savings.user
mybank.username me
You can also send the result straight to the X clipboard with the -p
option, or list available keys with the -l
option.
To setup a password store, you need to do the following:
-
Copy
pass
somewhere in your$PATH
.cp pass ~/local/bin
-
Create a gpg key if you don't already have one. Make sure you're using the gpg-agent for convenience.
gpg --gen-key echo use-agent >>~/.gnupg/gpg.conf
-
Create a repository for storing your data. If you choose another location, set
$PASS_HOME
to pointpass
to your repo.git init ~/.pass cd ~/.pass echo '# recipient: me@example.com' >pass.gpg echo '*.gpg diff=gpg' >.gitattributes git add . && git commit -m 'start pass repo'
-
Tell git how to show diffs between gpg files.
git config --global diff.gpg.textconv 'gpg -qd --no-tty'
-
Install the vim plugin to make editing gpg files easier.
mkdir -p ~/.vim/plugin cp gpg.vim ~/.vim/plugin
-
Add some content. Note that your commit messages are not encrypted.
cd ~/.pass vi pass.gpg git commit -am 'added password for mysite'
The gpg plugin does not care about the content of the file (so you can use it for other things besides pass data), with one exception: any lines at the beginning of the file starting with "# recipient: ..." specify gpg key-ids which should be able to access the encrypted file. Typically this will just be your email or key-id; but if you are sharing the repository, you may also list the other group members (make sure gpg knows about their keys, too).
The pass data itself is loaded via perl's YAML plugin, so any valid YAML
should work. The names of the elements are up to you, and you can make
hierarchies of arbitrary depth (e.g., myproject.host1.mysql.password
).
The query language is akin to XPath or CSS selectors, but much less
powerful (and hopefully simpler to use as a result). A key of the form
a.b.c
will look for a YAML element matching a
, which has a
sub-element matching b
, and so forth. Each part of the key is a
case-insensitive regex, and must match either the hash key of the YAML
element, or the value of the desc
field of the YAML element.
You may specify a key which is smaller than the full path. "Top" parts
of the hierarchy always match (so b.c
will match a.b.c
). "Bottom"
parts also match, so a.b
will match a.b.c
and a.b.d
). Elements
between key parts must be matched (so a.c
does not match a.b.c
).
If you use the pentadactyl
plugin for Firefox, there is a drop-in
plugin that can help with filling form fields from pass
data:
-
Copy the
autofill
plugin to your.pentadactyl
directory:mkdir -p ~/.pentadactyl/plugins cp pentadactyl/autofill.js ~/.pentadactyl/plugins/
-
Add a
url
field to your pass stanzas. E.g.:example: desc: My Example Site url: https://example.com user: foo password: bar
-
Auto-generate a mapping of URLs to stanzas:
pass --generate-autofill >~/.pentadactyl/pass.js
You can also do the mapping by hand if you do not want to keep the URLs in your password file (but take care to make your URL regexes sufficiently restrictive):
cat >~/.pentadactyl/pass.js <<\EOF plugins.autofill.add('^https://example\.com/', 'example'); EOF
-
Bind form-filling to a key (I use
Ctrl-F
), and load the mappings:cat >>~/.pentadactylrc <<\EOF loadplugins autofill runtime pass.js map :js plugins.autofill.fill(); imap :js plugins.autofill.fill(); EOF
With the steps above, hitting Ctrl-F
at example.com
will fill any
input elements that look like usernames with the contents of
example.user
, and any that look like passwords with
example.password
.
This system is undoubtedly full of bugs. It works for me, but hasn't received wide use. Due to offloading the cryptography to gpg, it is hoped that all bugs are query bugs, and not security bugs. Success (or failure) reports are welcome.
Setup could be simpler; possibly the system should provide a script to help the user setup their keys and repository.
The query system is ad-hoc. It has worked well in practice, but it may be that something like XPath would be more flexible, more standardized, and not too much harder to use.
Some people might prefer another format, like JSON, over YAML. I think YAML is easier for humans to write. The system could potentially allow both (since it never writes, but only reads).
It would be helpful to integrate with tools that want to access the passwords. I currently tie this to git with the following config:
[credential "https://github.com"]
username = peff
helper = "!f() { test $1 = get && echo password=$(pass -n github.password); }; f"
though you could also build a fancier helper around it (e.g., storing the URL along with the username and password, and then comparing it to the URL git is trying to access).
The pentadactyl extension is rather simplistic. It looks only for user
and password
in input elements; this matching heuristics probably need
to be expanded. Firefox's password manager already solves this problem,
and it would be nice if we could piggyback on that.