Share Encrypted Secret

Encrypt and share a secret. Everything is stored in the URL, nothing is stored or sent anywhere.

Signal, Keybase, WhatsApp, Ephemere, anything end-to-end encrypted.

How does it work ?#

Your secret is encrypted using TweetNaCl, with a secret_box cipher. The ciphertext (and nonce) is stored in the URL as a query string (which is public).

How the key is handled depends on how secure your channel of communication is. If using a secure channel, the key can be stored in the URL hash, which never reaches my server. It makes it more convenient as there is only one thing to share:

SecretTweetNaCl.secret_boxhttps://example.com?payload=ciphertext#keyVisible by the serverStays on the client

However, for unsecure channels (unencrypted chats like Messenger, Slack, email, etc), the key should travel separately. It's best to use a completely different method of communication to send it, eg: URL over Slack, key over Messenger.

What if...

We used a password to encrypt the key ?

Instead of sharing the key separately, we could encrypt it with a password, and ask for the password instead. But since humans are terrible at generating passwords, we might as well use the key directly as it's guaranteed to have more entropy.

We want an expiring link ?

This unfortunately requires some statefulness. If storing the ciphertext is not desired (larger size), the key could be split using Shamir Secret Sharing. One fragment would be shared in the URL hash, and the other sent to a Redis instance (or any auto-expiring KV store).

Details & Notes

This is abstracted in a little TypeScript package I made:

47ng/simple-e2ee

Simple end-to-end encryption for webapps
  • 7
  • 0
  • 6
  • v1.1.0
  • MIT License

Because a URL can only store so much data, your secret must be short (max 1024 characters, as the ciphertext + key will be quite longer).

If you liked this little encryption toy, check out Horcrux, a playground for splitting secrets with Shamir Secret Sharing.