- Security
- A
Islands and multiple personas on one device: how we make privacy part of the architecture
When building a private messenger, sooner or later you run into an uncomfortable question: what exactly protects the user, your promises or your architecture. Promises can’t be verified externally. So at RCQ, we made privacy rest on the device and data structure, not on the fact that we are good guys.
In this article, we'll cover two features that grew out of this approach: islands (your own server) and multi-account (multiple independent encrypted accounts on a single phone). And separately, without any sugarcoating, we'll lay out the limits of this approach.
1. Foundation: a server that knows as little as possible
First, a quick overview of the basics, otherwise the rest won't make sense.
- The identifier is a UIN, just a number. No phone number required, no contact list uploads. An account is not tied to your identity, you can burn it and create a new one in seconds.
- Sealed sender: the sender is sealed inside the encrypted envelope, not included in the header. At the transport layer, the server sees who the message is for, but not who it is from. Anyone who understands this will immediately see that the communication graph is not collected on the server.
- Content is end-to-end encrypted: ephemeral X25519 per message, HKDF, ChaCha20-Poly1305. The server only forwards ciphertext, and has no keys.
The idea is simple: the server is mostly just a dumb pipe for ciphertext. No phone numbers, no communication graph, no content. This is important for everything that follows.
2. Islands: your own server instead of ours
Since the server is just a dumb pipe, it can be hosted anywhere. Any organization (newsroom, law firm, team, NGO) can run its own RCQ instance, its own island, and communicate within it: its own server, its own UINs, its own history, its own groups, separate from the public network.
What does this provide in practice:
- No single large target. The public network is a single point of interest. One hundred separate islands are one hundred separate targets, and compromising one does not affect the others.
- Metadata (the tiny amount that exists at all) stays with the island owner, not with us.
- The question "what if you get pressured" is eliminated. If the server is yours, pressure will be applied to you, not to us, and you decide yourself what is stored on it. And as a reminder, there is barely anything to store.
Technically, the client is not tied to our domain: the server address is a configurable parameter. You can connect to the island directly during registration, or add an account on it later. Which leads us to the second part.
3. Multi-identity: multiple yous on a single phone
The task was stated as follows: provide a set of fully independent identities on a single device. Not just UI themes, but separate accounts: each with its own server, its own UIN, its own keys, its own contacts, and its own history. One for work on a corporate island, one personal for the public network, another one for some third purpose. And switching between them is instant, no re-logins and no app restarts required.
The main challenge here is not the UI, but ensuring that identities truly cannot leak into each other. If you cut corners, data from one will surface in another, and the entire concept becomes meaningless. That's why isolation goes all the way down, and the core of this whole system is the account's local UUID:
- The account registry only stores routing metadata: this UUID, the server address, and a label. It contains no secrets.
- Each account's secrets (UIN, token, private keys) are stored in an encrypted storage location prefixed with its UUID. There is only one physical file, but the slots do not overlap.
- Each account has its own message database, stored as a separate file with the UUID in its name. Threads are not mixed at the file system level.
- Favorites, archives, and unread counters are also organized under this prefix.
Switching is a hot rebuild: we terminate the current connection, redirect all storage locations to the UUID of the other account, re-read its database, and re-establish the socket. Externally this looks like an instant identity switch, internally it's a careful replacement of what data the running process is accessing.
There was extra work involved with upgrading old installations. If a user already had one account using the old scheme (without prefixes), it is silently wrapped into the first account of the registry on first launch: we generate a UUID, move the keys under it, and rename the database file. Nothing happens on the user's end, which is correct, as an upgrade should not break anything.
4. Honestly: what this does NOT protect against
This section is usually skipped out of embarrassment. We believe that without it, any text about security is a lie, so it's included here.
- This does not protect against infected devices. If Pegasus or a similar kernel-level implant lands on your phone, it can read everything after decryption, directly from the screen and memory. No messenger, neither Signal nor ours, protects against this. End-to-end encryption protects data from the network and servers, but not from someone who already has access to your phone. Anyone who promises immunity to Pegasus is lying.
- Forward secrecy is implemented differently across our platforms, and we need to be clear about that. On iOS, established sessions use Double Ratchet, so full forward secrecy is already in place. On Android, we currently use a simpler v=1 scheme without forward secrecy: if a long-term key is leaked, past correspondence linked to that key is exposed. Porting Double Ratchet to Android is our next immediate cryptographic task.
- There is no independent audit yet. The primitives are standard and proven, but "we wrote it carefully" is not the same as "this has been verified by an external party". An audit is on our roadmap, we are looking for funding for it. Until it is completed, we do not claim our product is "proven secure", and we advise you not to trust anyone who makes such claims.
A private messenger that does not disclose its limitations is more dangerous than an honest one: it creates a false sense of security.
Where all this stands
Islands and multi-account support are already live, this is the part we have fully rolled out. Forward secrecy on Android and key fingerprint verification (to prevent key substitution on the server side) are on our near-term roadmap, the audit is further out.
Client code is open, links are below the article. If you are the type of person who checks source code before trusting a product, we fully support that.
Write comment