Commit Briefs

1c49875f54 Paul W. Rankin

Tabify (master)


b7c076f4e9 Paul W. Rankin

Update copyright & email


66ad0c79e8 Paul W. Rankin

README.md: update clone url


e05199dfe5 Paul W. Rankin

Untabify


4874a84366 Paul W. Rankin

Update copyright & email


4944b4877a Paul W. Rankin

Wrap getopts in conditional


124e1ac4b0 Paul W. Rankin

Use /usr/local/share/man as default MANPREFIX


ede3b40a1c Paul W. Rankin

Fix to pass options to show()


595354a402 Paul W. Rankin

Remove unnecessary opts variable


63f8c962eb Paul W. Rankin

Attempt to minimise egregious tab spacing


Branches

Tags

This repository contains no tags

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/