Lots of prior work in this field (citation required), but I figured I could have
a go and see about leveraging the new WebCrypto
APIs.
poof
allows you to securely share secrets in a self-destructing, time-limited,
passphrase protected way.
- The server never sees the secret, or the passphrase.
- The server only ever releases the encrypted secret once, within the given time.
All data held in memory (by default) so server reload drops all secrets. It can be configured to persist data across reloads using an sqlite backed store.
A demo server is running at https://poof.0x6377.dev/.
But don't trust me --- run your own!
- Build from source with
go build
from the repo - Build from source and install with
go get github.com/thechriswalker/poof
Produces a single binary poof
that will run a web server on port 5000 or
specify a different port with -port=X
You have a secret you wish to share, but you don't want to paste the credentials into an email/IM.
The sharer uses the web client which:
- Asks for the secret,
a passphraseand a TTL. (passphrase is just randomly generated) - Uses the passphrase to derive an encryption key.
- Encrypts the secret with the encryption key.
- Creates a hash of the encryption key.
- The client calls out to the server and sends the encrypted secret and the hash of the passphrase.
- The server stores both the encrypted secret and the hash of the passphrase and the expiry and returns an opaque key.
The sharer gives the key and the passphrase URL (which contains the
passphrase and key in the hash fragment) to the recipient, who then uses the web
client which:
Asks for the key (although this is probably encoded in the URL)Gets the key from hash fragmentAsks for the passphraseGets the passphrase from hash fragment, derives the key and hash- Calls out to the server for with the key and the hash.
- The server checks the key and the hash (and the expiry) and if OK, returns the encrypted secret and destroys the record
- The client decrypts the secret and displays to the recipient.
-
/send
HTML Client for creating a secret to share -
/recv#key=<key>&pass=<pass>
HTML Client for receiving a secret -
POST /api/send
withenc=<encrypted secret>&hash=<hash of passphrase>&ttl=<seconds to keep>
returns JSON{"key": "<key or null>", "errors": ["<string>"]}
-
POST /api/recv
withkey=<key>&hash=<hash>
returns JSON{"enc":"<encrypted secret or null>","errors": ["<string>"]}
-
GET /api/stats
returns JSON with counts of size of current set, number of secrets added, burned, expired (reset at reload of service)
That's it.
Because I fancied doing as much of this in the client with JS as possible as an experiment in WebCrypto. As such support is limited to browsers with proper WebCrypto support.
Seriously, go watch Arrested Development. It's awesome -- you won't regret it.