Password management is becoming increasingly important. Best security practices suggest using difficult to remember passwords consisting of either long string of unconnected words or randomized alphanumeric strings. These per-password difficulties are compounded by the increasing number of services brought about by the digitization of everything. While there are certainly efforts the improve this space, they all have specific limitations and the non-emergence of a widely adopted solution tells just how significant these limitations are.

A modern password management solution must:

  • Sync across multiple devices: Passwords must be available in a variety of scenarios and environments to be useful.
  • Allow mutable secrets: Many services require periodic password updates, this should have first-class support.
  • Secure storage and retrieval: What good are secure passwords if you can not trust the central repository to securely store them.
  • Present a simple UI: No solution is viable if you can not actually find your passwords.

Stash is a password management script in my scripts repository. Aligned with my usual design goals - it presents a minimalistic, lightweight application with a simple interface, favoring simplicity over robust functionality. The basic architectural design choices may be summarized as:

  • GPG encrypted password file: Data is stored in a single file, which is gpg encrypted. This means to decrypt the data you must posses (1) encrypted password file, (2) gpg private key, and (3) gpg private key password.
  • Hierarchical <key,value> password definitions: I am a huge fan of simple <key,value> stores. I think they provide extensibility and meld well with different use-cases.
  • Use commodity linux tooling: Should be deployable as a simple shell script without having to install myriad dependencies.

Usage

The script usage is quite simple. To begin we will call help to show the usage.

hamersaw@ragnarok:~$ stash help
USAGE: stash COMMAND
COMMAND:
    clip                copy a key's value to the clipboard
    get <key>           retrieve a value for the specified key
    help                display this help menu
    init <gpg-username> initailize the stash repository
    list [subkey]       find all keys containing the specified subkey
    recover             fix system following a failure
    set <key> <value>   store the value for the specified key
    unset <key>         remove values for the key (and all subkeys)
    version             display the applications version

Initializing a stash storage file can be performed by calling init with the gpg id of the private key to use for encryption. By default the storage location is $HOME/.local/share/stash but can be manually configured by setting the stashdir ENV variable.

hamersaw@ragnarok:~$ stash init hamersaw@protonmail.com

We can set passwords by using the set command. Note that the hierarchical definition uses periods as the delimiter.

hamersaw@ragnarok:~$ stash set email.google.username foo
hamersaw@ragnarok:~$ stash set email.google.password bar
hamersaw@ragnarok:~$ stash set email.protonmail.username foo
hamersaw@ragnarok:~$ stash set email.protonmail.password baz

Listing the available passwords with the list command optionally takes a prefix argument. I often combine this with grep to easily search my password store. For example:

hamersaw@ragnarok:~$ stash list email.protonmail
email.protonmail.password
email.protonmail.username
hamersaw@ragnarok:~$ stash list | grep protonmail
email.protonmail.password
email.protonmail.username

And calling get rather than list will print off both the key and value for each password.

hamersaw@ragnarok:~$ stash get email.google
email.google.password bar
email.google.username foo

Using clip uses the xclip utility internally to copy the password value to the clipboard without printing it to the screen.

hamersaw@ragnarok:~$ stash clip email.protonmail.password

Unsetting a password can be done using the unset command. Note that this works hierarchically, so unsetting email.google will unset both the email.google.username and email.google.password keys.

hamersaw@ragnarok:~$ stash unset email.google
hamersaw@ragnarok:~$ stash list
email.protonmail.password
email.protonmail.username

And finally recover is used during failure scenarios. Stash uses a CoW mechanism to ensure that any failure is easily recoverable.

hamersaw@ragnarok:~$ stash recover

This post is part 5 / 5 of the Script Series:

  1. Introduction
  2. A Script for Managing Dotfiles
  3. Due: A Kanban TODO List Script
  4. Scripting Your UI Color-Palette
  5. Password Management with Stash

11 day(s) offloaded in the 100DaysToOffload challenge.