In version 4.1.0, we encrypted messages just like expenses and budgets — with the user's own Data Encryption Key. That meant your messages were protected from outsiders. But there was a gap: the server still held all the keys to decrypt them because the server managed the encryption flow.
For financial data, that's acceptable. For private conversations between two people? Absolutely not.
Why Server-Side Encryption Isn't Enough for Messages
Here's the uncomfortable truth about most 'encrypted' messaging: the server orchestrates the encryption and holds the keys. If the server is compromised, all messages are readable. If the service receives a subpoena, they can hand over unencrypted data. If a rogue employee accesses the database, conversations are exposed.
For a finance app that also handles private messaging, this was an unacceptable liability. Two users discussing a shared debt, a joint purchase, or financial advice deserve the same privacy guarantees as Signal or WhatsApp — not the security theater of most web apps.
True E2EE. Not 'server says it's encrypted.'
We implemented ECDH P-256 key exchange so each message pair has its own unique encryption key. Neither party's private key ever touches our servers. We couldn't read your messages if we tried.
How ECDH P-256 Key Exchange Works
ECDH (Elliptic Curve Diffie-Hellman) is the same cryptographic primitive that powers Signal, WhatsApp, and Apple iMessage. Here's the simplified flow: each user generates an ECDH P-256 key pair. When User A wants to message User B, they fetch B's public key from the server, derive a shared secret using their private key and B's public key, and use that shared secret as the AES-256-GCM encryption key.
The critical property: the shared secret is mathematically identical regardless of who derives it (A derives it from A's private + B's public, B derives it from B's private + A's public), but can never be computed from the public keys alone. The private keys stay on the users' devices. The server only stores public keys. Even if the entire database is leaked, messages remain unreadable.
Performance: Encrypting Without Slowing Down
ECDH key exchange is computationally expensive. Doing it on every message send would create unacceptable latency. Our solution: the MessageKeyManager. It caches derived shared secrets in RAM for active conversations, so subsequent messages between the same pair use the cached key with zero additional computation.
We also cache ECDH public keys in IndexedDB with a generous TTL, eliminating redundant key fetches. The result? Message encryption adds less than 5ms of latency — completely imperceptible to users — while providing military-grade privacy.
The Security Audit That Proved It Works
Before shipping, we conducted a comprehensive security audit of the entire ECDH pipeline. We verified that private keys never leave the client, that the key exchange is resistant to man-in-the-middle attacks (protected by our existing authentication layer), and that the AES-256-GCM IV implementation prevents reuse attacks.
We also identified and fixed edge cases: what happens when a user's device is lost? (Their message cache is encrypted with DEK — still protected.) What about group messages? (Groups use a different model — each member encrypts with the group's shared DEK, which is itself encrypted per-member.)
Privacy Isn't a Feature. It's the Architecture.
Version 4.4.0 completed the Simple Message encryption story. We now have what few web applications can claim: true, auditable, end-to-end encrypted messaging where the service provider has zero ability to read user conversations. Not because we promise not to. Because the mathematics make it impossible.
This is the standard for private communication online. We're proud to meet it — and we think your financial conversations deserve nothing less.
