Orbyte
An end-to-end encrypted messenger
Orbyte is an encrypted messaging application in the spirit of Session: private conversations that do not require a phone number to start, and a server that is designed to know as little as possible. It is in active development — the parts that are built are built carefully, and the parts that are not are honestly labelled as such.
- My role
- Solo — architecture, cryptography design and implementation
- Built with
- TypeScript
- React
- Next.js
- Node.js
- PostgreSQL
- Docker
Vision
Why this exists
Most messengers protect the contents of your conversations and quietly leak everything around them. Who you talked to, when, how often, from which number. The message body is encrypted; the social graph is not, and the social graph is frequently the more sensitive of the two.
Orbyte starts from the assumption that the server is hostile, or will eventually be compelled to behave as if it were. That means no phone number as an identifier, no plaintext contact list, no readable metadata sitting in a table waiting for a subpoena or a breach.
This is a learning project with a real target, not a product pretending to be finished. Building a messenger is the fastest way I have found to understand why the primitives are shaped the way they are — and I would rather learn that by implementing it against a threat model than by reading about it.
Objectives
What it has to get right
Constraints stated up front, so the design decisions further down have something to be measured against.
End-to-end encryption by default
No opt-in, no 'secret chat' mode. If encryption is a setting, most conversations are unencrypted.
No phone number, no real identity
Accounts are key pairs. Signing up should not require handing over the one identifier that links you to everything else you do.
Minimal metadata retention
The server stores what it needs to route and deliver, for as long as it needs to, and nothing more.
Verifiable, not trusted
Key fingerprints users can compare out of band, so security does not rest on believing the server.
Interface
What it looks like
/projects/orbyte/conversation.png
/projects/orbyte/verification.png
Features
What it does
Key-pair identities
An account is a keypair generated on device. There is no phone number, no email, and no directory mapping you to a real-world identifier.
End-to-end encrypted messages
Content is encrypted client-side. The server relays ciphertext it cannot read and never holds a private key.
Forward secrecy
Ratcheted session keys, so compromising a device today does not retroactively decrypt yesterday's conversations.
Out-of-band verification
Short fingerprints users can compare in person or over another channel to detect a man-in-the-middle.
Sealed sender routing
Sender identity is not readable by the relay, so delivery does not require the server to learn the social graph.
Disappearing messages
Per-conversation expiry enforced on the client and reflected in server retention.
Architecture
How it is put together
The design constraint is simple to state and inconvenient to satisfy: assume the server operator is an adversary. Anything the server can read, it will eventually be asked to hand over. So the architecture is a negotiation over how little it can be given while still delivering messages.
Client
Owns all key material. Generates identity keys, performs the handshake, encrypts and decrypts, and holds the only readable copy of a conversation. Keys never leave the device unencrypted.
- TypeScript
- React
- WebCrypto
Relay
Accepts and forwards ciphertext envelopes. Holds queued messages until delivery, then drops them. Deliberately built so that reading the database tells you almost nothing.
- Node.js
- WebSocket
- PostgreSQL
Key distribution
Publishes pre-key bundles so a first message can be sent to someone who is offline, without either party trusting the server about the other's identity.
- REST API
- Signed pre-keys
Infrastructure
Containerised deployment with short log retention and no message content in logs — the fastest way to accidentally build a plaintext archive is verbose logging.
- Docker
- Linux
- Reverse proxy
Decisions worth defending
Standard primitives, no invented cryptography
Established constructions, standard libraries, no bespoke algorithms. The interesting problems in a messenger are key management and metadata, not inventing a cipher — and inventing one is how projects like this fail.
Identifiers are keys, not phone numbers
Phone-number identity is the single largest metadata leak in mainstream messengers. Removing it costs discoverability, which is a trade worth making here.
The relay is treated as untrusted infrastructure
Every design review question starts with 'what does a dump of this database reveal'. If the answer is uncomfortable, the schema changes.
Retention is a deletion policy, not a storage policy
Queued messages are removed on delivery and expired on a timer. Storage you never had cannot be disclosed.
Challenges
The parts that were actually hard
Problem, what I did about it, and where that landed. Including the ones still open.
Problem
Key management is where messengers actually break — not in the cipher, but in what happens when someone changes device or reinstalls.
Approach
Treating device changes as a first-class flow rather than an afterthought: explicit identity key rotation, a visible warning to contacts when a fingerprint changes, and no silent re-keying.
Outcome
A key change is something the other party sees and can question, instead of something the server can quietly perform on their behalf.
Problem
Encrypting content is straightforward. Not leaking who is talking to whom is not.
Approach
Studying sealed-sender designs and pushing routing information into the encrypted envelope wherever the relay does not strictly need it in the clear.
Outcome
Work in progress, and the part of the project I am learning the most from — metadata resistance is a spectrum, not a checkbox.
Problem
Doing cryptography in a browser environment means dealing with key storage that was never designed for secrets.
Approach
Non-extractable WebCrypto keys where the platform supports it, and an explicit inventory of what is actually persisted versus held in memory.
Outcome
A clear, written threat model of what a compromised device gets — including the parts I cannot defend against.
Learned
What it taught me
Reading a protocol specification and implementing it are entirely different activities. The specification is where the assumptions hide.
Threat models have to be written down. Held in your head, they quietly expand to whatever the current design happens to defend against.
Encrypted content plus plaintext metadata is a much weaker guarantee than it appears in a marketing page.
Usability and security genuinely conflict here, and pretending otherwise produces something nobody uses.
The right amount of custom cryptography in a project like this is zero.
Roadmap
Where it goes next
Shipped, in progress and planned — kept honest about which is which.
Core protocol
- Identity key generation and storage
- Session establishment and message encryption
- Relay with queued delivery
- Fingerprint verification UI
Usable client
- Multi-device support
- Disappearing messages
- Attachments with encrypted blob storage
- Push delivery without leaking recipients
Hardening
- Written, published threat model
- External review of the cryptographic design
- Reproducible builds
- Metadata-resistance improvements to routing
Next
Other projects
Hackuten
A CTF platform for learning cybersecurity
Hackuten is a capture-the-flag platform covering several areas of cybersecurity — web, reverse engineering, cryptography, forensics and more. It exists to make the first steps into the field less discouraging: challenges that teach something specific, in an order that makes sense, with infrastructure that does not get in the way.
Read moreBatelys
Lone worker safety, one button at a time
Batelys protects people who work alone. You check in when you arrive, then press a button now and then to confirm you are fine. Miss a check-in — because you fell, collapsed, or simply cannot reach your phone — and an alert leaves on its own, with your position, escalating through your chain until someone responds.
Read more
