Tree


LICENSEcommits | blame
Makefilecommits | blame
README.mdcommits | blame
pw.1commits | blame
pw.shcommits | blame
pw_alias.shcommits | blame

README.md

pw - POSIX shell password manager
=================================

pw is a rewrite of Roman Zolotarev's POSIX shell password manager [pass][1].

I've used a new name to avoid confusion with the more well-known
[pass][2], it's 50% quicker to type, and also because it's my initials.


Requirements
------------

- [`openssl`][3] handles all encryption processes
- [`urandom`][4] is required for generating random passwords
- [`oathtool`][5] 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 anon@rnkn.xyz: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


[1]: https://www.romanzolotarev.com/pass.html
[2]: https://www.passwordstore.org
[3]: https://man.openbsd.org/openssl
[4]: https://man.openbsd.org/urandom
[5]: https://www.nongnu.org/oath-toolkit/