Conversations between a manager and an employee about expenses can touch salaries, health claims, travel plans, and disputes. That’s why chat in Reimbilly is end-to-end encrypted: messages are encrypted on your device before they leave it, and only your conversation partner can decrypt them. Not our servers, not our staff, not a subpoenaed database dump.
The building blocks
We use NaCl “box” encryption (the libsodium/TweetNaCl construction built on Curve25519, XSalsa20, and Poly1305). Every user gets a keypair generated on their own device. The private key never leaves the device — it’s stored in the platform secure enclave (Keychain on iOS, Keystore on Android). Only the public key is uploaded, so others can encrypt messages to you.
Sending a message
- Your app fetches the recipient’s public key.
- It generates a fresh random nonce for this one message.
- NaCl box encrypts the message with your private key + their public key + the nonce.
- The ciphertext and nonce are stored on the server; the plaintext never leaves your phone.
- The recipient’s device reverses the process with their private key and your public key.
What our database stores per message: sender id, conversation id, timestamp, a base64 ciphertext blob, and a nonce. What it can reveal about the content: nothing.
Honest limitations
E2E encryption protects message content, not metadata — we necessarily know who talked to whom and when, or the app couldn’t deliver messages. And if you lose every logged-in device, encrypted history is unrecoverable by design; no “support backdoor” exists. We think that trade-off is exactly right for financial conversations.