pw - POSIX shell password manager
pw is a rewrite of Roman Zolotarev's POSIX shell password manager pass.
I've used a new name to avoid confusion with the more well-known pass, it's 50% quicker to type, and also because it's my initials.
Requirements
openssl
handles all encryption processesurandom
is required for generating random passwordsoathtool
is required for generating TOTPs
Installation
The first step is to read and understand the source. I encourage you not to encrypt your password data using a program you do not understand. (As a fail-safe, pw requires its default directories to be manually created.)
After that:
$ git clone git://git.bydasein.com/pw.git
$ cd pw
# make install
or
$ make PREFIX=$HOME install
Usage
pw [COMMAND] [ENTRY]
pw [COMMAND] -h
Commands:
init
initialize RSA key pair
ls|list [QUERY]
list entries matching QUERY or list all
add <ENTRY>
add ENTRY from STDIN or prompt for multiline text
show <ENTRY>
decrypt and show ENTRY or ENTRY FIELD or ENTRY TOTP
ed|edit <ENTRY>
temporarily decrypt ENTRY and edit in EDITOR
gen|generate [LENGTH]
generate random password of LENGTH (default 16)
sign <ENTRY>
create signature for ENTRY with private key
verify <ENTRY>
verify ENTRY against signature with public key
git <ARGUMENTS>
call git and pass ARGUMENTS verbatim
master
change private key password
All configuration is accomplished via environment variables:
PW_PUBLIC_KEY location of public key
PW_PRIVATE_KEY location of private key
PW_DIR location of password directory
PW_MASTER private key password (see below)
PW_SIGN when set, sign password tarballs
PW_VERIFY when set, verify password tarballs
PW_CLIP clipboard program name
To avoid needing to enter your private key password with every invocation of
pw, set the PW_MASTER
environment variable to your private key password.
For convenience, add the following aliases to your profile:
alias pw_unlock="stty -echo; read -r PW_MASTER; stty echo; export PW_MASTER"
alias pw_lock="unset PW_MASTER"
How it works
pw uses hybrid encryption, which combines the strengths of RSA asymmetric encryption with AES symmetric encryption.
For example, adding a password for example.com
generates an encryption key and
the password content is then encrypted with this key using AES-256-CBC
encryption, as example.com.enc
. The key is then encrypted using your RSA
public key as example.com.key
and the original key discarded. Both
example.com.enc
and example.com.key
are added to a tarball
example.com.tar
, and an optional signed hash example.com.tar.sig
is
generated using your RSA private key.
This is the resulting hierarchy:
.PW_DIR/
├── example.com.tar
│ ├── example.com.enc
│ └── example.com.key
└── example.com.tar.sig
Bugs
Please email patches to the address in the source.
Hints
To add a generated password:
$ pw generate | pw add example.com
To generate a new password for an existing entry in-place:
$ pw show example.com | sed "1d; i\\
> $(pw generate)
> " | pw add -f example.com
Set git to perform binary diffs:
$ cd .pw
$ cat > .gitattributes
> *.tar diff=
> *.tar.sig diff=
To import from password-store
:
$ pw_unlock
$ cd $HOME/.password-store
$ for file in *.gpg; do
> entry="${file%.gpg}"
> pass "$entry" | sed -E 's/^otpauth:.*secret=([A-Za-z2-7]+).*/totp: \1/' | pw add "$entry"
> done
To batch edit all entries, e.g. to change an email:
$ pw_unlock
$ pw ls | while read -r entry; do
> pw show "$entry" | sed 's/@example\.com/@newaddress.com/' | pw add -f "$entry"
> done
To rotate your private key:
$ tar -cvf keybackup.tar $HOME/.keys
$ PW_PRIVATE_KEY=$HOME/.keys/newkey.sec \
> PW_PUBLIC_KEY=$HOME/.keys/newkey.pub \
> pw init
$ mkdir $HOME/.pw_new
$ pw_unlock
$ pw ls | while read -r entry; do
> pw show "$entry" |
> PW_PUBLIC_KEY=$HOME/.keys/newkey.pub \
> PW_DIR=$HOME/.pw_new \
> pw add "$entry"
> done
$ mv $HOME/.keys/{newkey,pw}.sec
$ mv $HOME/.keys/{newkey,pw}.pub
$ rm -rf $HOME/.pw
$ mv $HOME/.pw_new $HOME/.pw