How RetroRelay works
The short version
- The web dashboard runs over standard HTTPS. The retro-phone link runs over plain HTTP with ChaCha20-Poly1305 layered on top, the same cipher TLS 1.3 uses, because J2ME phones generally can't validate modern TLS certificates.
- Authenticator secrets, OAuth tokens, and two-step verification seeds live in Firestore encrypted with AES-256-GCM, sealed to your account so a stolen ciphertext can't be moved between users.
- We don't sell data, run ads, track individuals, or use your data to train AI models. The anonymous counters and diagnostic events we do keep are listed in full on the Privacy page.
Three places, two encrypted links
RetroRelay has three moving parts: a small Java app that runs on the retro phone, a server, and this web dashboard. The two links between them use different kinds of encryption because the phone and the browser have very different things they can prove about themselves.
What crosses the wire
- Phone ↔ Server: Short requests for the screens the phone displays. Confidentiality and integrity come from the ChaCha20-Poly1305 encryption layer; the wire underneath is just HTTP.
- Dashboard ↔ Server: JSON over
HTTPS, with your Firebase ID token in the
Authorizationheader. Standard modern browser cryptography, the same kind any HTTPS site uses. - Server ↔ Firestore: The server reads and writes your data using a service-account credential that lives only in the server's environment. The browser never reaches Firestore directly except for the small read-only slice of your own account record.
What never crosses the wire
- Your card details. Stripe-hosted checkout accepts the card in your browser and posts it to Stripe directly. We see a customer ID and a subscription status, nothing more.
- Your authenticator seeds, in online mode. By default the seed that generates your codes never leaves the server; only the momentary six-digit code is sent to the phone, for the one request that asked for it. Offline mode is the opt-in exception: the seed is downloaded once, encrypted, so codes keep working without signal.
How a phone meets your account
Your retro phone shows a one-time code, you enter it on the dashboard, and the two are introduced and remember the pairing until you remove it.
- Install. Get the app onto your retro phone either downloaded over the air from a short URL, or copied across via USB or Bluetooth.
- Open. The first app launch shows a six-digit code. The code is good for a few minutes; if it expires, the next launch shows a fresh one. Nothing about your account is on the phone yet.
- Confirm. Sign in to the dashboard on any modern browser, open the Pair Device screen, and type the six digits. The dashboard tells the server “this phone is mine”, the server tells the phone, and the phone places you onto the main menu.
From that moment on, every request the phone makes is identified using a session token issued during pairing. The phone can be unpaired from the dashboard or from the phone's own Settings screen and both ends forget the token immediately; the phone is back to a fresh six-digit code on next launch.
Which phones, and how they connect
RetroRelay targets the era between 2003 and 2013: the window when J2ME (Java ME) was the lingua franca of every non-Apple, non-Android phone on the shelf. The app is built on MIDP 2.0 over CLDC 1.0, the widest possible J2ME baseline, which means the app runs on virtually every retro phone of the period.
2G
The longer question for a 2003-2013 phone is not whether it runs RetroRelay, it almost certainly does, but whether the local mobile network still speaks the radio standard the phone knows. That answer varies a great deal by country and carrier: the UK has the longest known runway (O2 is committed to keeping 2G alive until 2033 to back the national smart-meter network), much of the EU is in the middle of retiring 2G now, and the US is essentially done.
The full country-by-country picture, and what to do where 2G has already gone, lives on the How to connect page, which we review as time goes on.
Wi-Fi
Where 2G has already gone, the answer is Wi-Fi. The phone reaches the server through an in-range Wi-Fi access point, or a personal hotspot shared from a modern phone, rather than the cellular radio. Many 2007-onwards phones have working Wi-Fi already; on those, it's the dependable route once the local network has moved on.
Built for the slowest phone, not the fastest
Running on a 2003-2013 phone and running well on one are different problems. The oldest phones RetroRelay targets interpret their Java one instruction at a time, with none of the just-in-time compilation a modern phone takes for granted. A phone from around 2007 onward runs the very same app roughly thirty times faster without changing a line. So the work was never aimed at the fast phones; it was aimed at the slowest one in the room, because once that one feels quick, every newer phone already does.
On a phone like that, speed is almost exactly the number of operations the processor has to perform. So we put emphasis on reducing the number of operations those phones have to interpret as much as possible, without sacrificing security or features, and measured each one on real hardware rather than an emulator.
Small screens, small payloads
The phone and server speak a compact binary protocol, not a web page. A typical screen is a few hundred bytes on the wire, which is what keeps the app responsive on a 2G connection where every kilobyte is felt. Where data arrives over a slow radio, the phone begins decrypting and unpacking it as it streams in, rather than waiting for the whole reply to land.
The phone's own look, not ours
RetroRelay draws its screens with each phone's built-in menus and lists rather than painting a custom interface of its own. The phone lays itself out the way its maker intended, so one application feels native across screens and keypads that have almost nothing else in common, instead of one fixed design stretched awkwardly across all of them.
A lighter mode that turns itself on
On first launch the app quietly times itself with a tiny CPU benchmark, and on the very oldest phones it switches on a performance settings preset so the slowest phones stay smooth from the very first screen. There's nothing to set up, the phone decides once and a faster phone simply keeps the default settings.
The performance settings preset is a small set of choices the phone owns, all gathered in Settings under Performance: a faster list-style display that skips decorative images, lighter background syncing, and a mode that only pulls Habit, Task, & Event data when you ask for it. Each one is yours to change the moment you'd rather have the richer behaviour.
Working without signal
A retro phone may lose signal sometimes. RetroRelay is built for that. It keeps a local copy of whatever it has already synced, so a dropped connection quietly narrows what you can do rather than blanking the screen.
Authenticator codes, offline
The authenticator runs in one of two modes. In its default mode each code is fetched fresh from the server on demand, which keeps the seeds off the phone entirely. Turn offline mode on, and the phone keeps an encrypted copy of your seed list in its own local storage, so the codes continue to refresh without any need for an internet connection.
It's the same six-digit TOTP code either way; the only difference is where the seed lives. The cache is encrypted with the same construction the transport layer uses. See Encrypted in transit and at rest for the cipher details.
What's already on the phone
Your habits, tasks, and events, are drawn on the phone from data it has already pulled, so you can open and read them with no signal at all, you're simply looking at your last-synced view rather than a live one. Weather is cached the same way: the most recent forecast is kept on the phone in the background, whether or not you've checked the weather feature, so it's there to glance at offline.
Some changes don't need a connection to feel done. Completing, reopening, or deleting a task, checking off a habit, and deleting an event or responding to an invitation all work offline: the change takes effect on screen straight away and is held in an encrypted queue on the phone, then sent for you automatically the moment signal returns. An “Outbox” entry lists what's still pending and lets you undo anything before it goes, the same familiar shape as a text message written offline and delivered when you resurface.
What still needs signal
Anything that fetches something new, or hands work to a connected service, needs the phone to reach our servers: refreshing weather, pulling the latest from a connected service, creating or editing a habit, task, or event, changing a setting that lives on your account, and pairing a new device.
Unpairing without signal
Unpairing doesn't wait for an internet connection, it immediately wipes the data and pairing token held on the phone. Useful if you're about to hand the phone on to someone else, and can't get online first. Normally unpairing removes the phone from the dashboard, but because it can't reach our servers when offline, the phone will still appear on your dashboard afterwards; remove it there too when you're next online to fully retire the pairing.
Encrypted in transit and at rest
Most consumer software gets vague when describing its security. You're trusting a retro phone and a cloud account with real secrets, possibly your authenticator seeds; the least we can do is name the algorithms and link the standards that specify them, so you can decide for yourself whether the design fits your risk tolerance.
Phone transport & storage: ChaCha20-Poly1305
Every authenticated request from or to a paired retro phone is wrapped in a modern authenticated-encryption layer. The cipher is ChaCha20-Poly1305, the same one TLS 1.3 uses for its no-hardware-AES software path.
A passive observer on the network, an open-Wi-Fi sniffer, an ISP-level packet capture, can all see that a request is happening, but cannot read its contents, cannot modify it without the integrity check failing, and cannot replay an earlier capture against a fresh session. A J2ME phone was never given the ability to understand modern HTTPS, and trying to give it this ability and maintain it would be its own major liability. The AEAD wrapper is the answer to that constraint.
The phone also encrypts locally stored data worth protecting: your Authenticator seeds (in offline mode), your connected-service data, and any actions you've queued while offline. Each is sealed on the phone with the same ChaCha20-Poly1305 construction the transport layer uses.
At rest in Firestore: AES-256-GCM
Three kinds of fields in Firestore are encrypted before they're written: TOTP secrets (the base32 seeds that generate your authenticator codes), OAuth tokens (the access and refresh tokens that connected integrations depend on), and two-step verification seeds (the secret behind the second factor on your own RetroRelay account). The construction is AES-256-GCM in the standard NIST envelope, with a fresh random nonce on every write.
Each blob is cryptographically bound to the account that owns it. A ciphertext sealed for one account cannot be moved into another. The binding is enforced inside the cipher itself, not by application logic.
Key derivation: HKDF-SHA256
The keys that protect your data aren't shared across jobs. Each one is derived for its own purpose with HKDF-SHA256 (RFC 5869), the standard behind the same key schedules used in TLS 1.3. The key that seals your OAuth tokens and the key that encrypts a phone session are cryptographically separate, so neither reveals anything about the other.
Why ChaCha20-Poly1305 specifically
The cipher choice on the phone wasn't a fashion call. A 2005-era ARM7 chip phone has no AES hardware acceleration. Hardware-accelerated AES didn't reach most mobile silicon until around 2013. On the phones RetroRelay targets, an AES implementation would have to run in pure Java, slowly, and through the kind of table-lookup patterns that have historically leaked the key on no-hardware-support paths.
ChaCha20 was designed for exactly this case. Daniel J. Bernstein published it in 2008, specifically as the no-hardware-AES software cipher. Only 32-bit add, rotate, and XOR, with no S-box lookup tables that could leak through cache timing. Adam Langley at Google adopted the construction for Android TLS in 2013 (the smartphone version of the same problem we face on retro phones), and TLS 1.3 standardised ChaCha20-Poly1305 in 2018 for the same software-only-path reason.
What to be aware of
The design above is the strongest set of defences 2003-2013 hardware allows. The encryption on the phone protects what's stored on it against casual access, but not against someone determined who has the phone in hand. A retro phone has to open its own caches with no server and no signal, so the material that unlocks them necessarily lives on the phone too. That's the shape of the hardware, not a corner we cut.
It helps to think of the paired phone as a physical key. If you lose it, unpair it from the dashboard as soon as you can. This stops our server trusting it straight away, and the phone erases its stored copy the next time it reaches us. The one gap is a phone kept deliberately offline: it never hears that it's been unpaired, so if you'd switched the Authenticator to its offline mode, whoever holds it could keep reading those rotating codes (and anything else cached for offline use) until it comes back online.
This is the ordinary trade-off of any offline authenticator, not something peculiar to us, they all keep their seeds on the phone so codes work without signal, and all show those codes to anyone holding an unlocked phone. A modern phone hides them behind a lock screen and a fingerprint; a retro phone, without either, leans a little more on the owner.
Look after your retro phone the way you'd look after a wallet or a front-door key. We recommend keeping it close, knowing where it is, and unpairing it if it ever wanders off.
Verifiable references
- RFC 8439 ChaCha20 and Poly1305 for IETF Protocols. The phone↔server transport layer and the phone-side TOTP offline cache.
- RFC 6238 TOTP: Time-Based One-Time Password Algorithm. The codes the phone displays.
- RFC 4226 HOTP: HMAC-Based One-Time Password Algorithm. The counter-based predecessor TOTP builds on.
- RFC 5869 HKDF: HMAC-based Extract-and-Expand Key Derivation Function. The at-rest key tree.
- NIST SP 800-38D Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (AES-GCM). The at-rest envelope.
- RFC 6749 The OAuth 2.0 Authorization Framework.