Why not use push notifications instead of polling?
Push notifications are a privacy compromise we don't want to make. The two
planet-scale push pipes — Apple Push Notification Service (APNs) for iOS and
Firebase Cloud Messaging (FCM) for Android — only work if our server hands every
outgoing message to Apple or Google first, addressed to a per-device token that
we'd have to keep in our database alongside the user identity. That single design
decision would force us to learn, store, and reveal a long list of things we
deliberately don't know today: which of our users are on iPhones and which are on
Android, the device-level identifier those vendors use to track them across every
app they've ever installed, and the precise timing and frequency of every
conversation each user is part of. Even with the message body fully encrypted, the
metadata trail — this user, this token, at this minute, woken by a message
from someone — is exactly the surveillance signal that's most useful to anyone
with subpoena power or a court order to compel Apple and Google.
The EFF has spent years documenting how this design has already been used against
journalists, activists, and ordinary users by federal and foreign governments
alike, because push metadata sits in two of the largest centralized aggregation
points on the internet and law enforcement has learned exactly how to ask for it.
Long-polling has none of these properties: the client opens an authenticated
connection directly to our server when it wants new messages, the connection is
end-to-end encrypted and short-lived, no third party ever sees that the
conversation happened, and no per-device token tying a real-world identity to a
vendor account ever leaves the user's phone. We pay a small battery cost for that
guarantee, and we think it's worth it — the entire reason this server exists is
to keep the metadata you don't want shared from being shared.
What does the server actually know about me?
Very little, by design. The server stores two SQLite tables: a
Principals row per user containing a random hex user id, your auth
token (and a hashed copy of it for at-rest defence), and the type of principal
(user or group); and a Messages queue holding pending notifications
whose payload bodies are opaque encrypted blobs. There is no phone number, no
email address, no display name (your display name lives only inside the encrypted
payload, where the server can't read it), no contact list, no device push token,
no IP geolocation, and no link between your user id and any real-world identifier
you didn't deliberately share inside an encrypted message.
Your user id is generated on our side as a random 64-bit hex string when you
register — we don't ask you for it and you don't pick it, which means it
can't accidentally match a username you use elsewhere. The only network metadata
the server briefly handles is the IP address of the open polling connection (used
to route the response back and then immediately forgotten), and a per-user
action-rate counter that lives in memory and is discarded when the process
restarts. The full set of fields the server can observe is published in the
API reference; if a field isn't in the schema there, the
server doesn't see it.
What happens if your server is seized or subpoenaed?
A seizure of the server — or a court order compelling us to hand over its
contents — would yield two SQLite files and a short-lived log. The
user.db file contains random user ids and authentication tokens
(themselves rotated to hashed form at rest). The msg.db file contains
any messages that happen to be sitting in the delivery queue at that exact
moment, addressed to recipient user ids, with the message bodies being base64
ciphertext that we cannot decrypt because we don't hold the keys. Old messages
are deleted on a janitor schedule, so the queue is small even at the worst time.
What that seizure would not reveal: the plaintext content of any
message, the display names of any users, the social graph of who-talks-to-whom
across conversations (group fan-out is keyed on group ids, not member-pair lists),
phone numbers, email addresses, real names, IP histories, or push tokens that
could be cross-referenced with Apple or Google records. We can't be compelled to
produce what we don't have. Compare this with the trove a comparable subpoena
against a phone-number-based chat service would surface — this difference
is the whole reason for the design.
Why don't you ask for a phone number or email when I sign up?
Because every chat app that does ask for one becomes a phone book that can be
subpoenaed, leaked, or cross-referenced with other breaches. A phone number ties
your account to a billing identity, a SIM-card registration, and an OS-level push
token; an email address ties it to whatever surveillance footprint that email
already has across the rest of the internet. Once we've collected either, we
can't ever truthfully claim not to know who you are. So we don't collect either.
Your account is a random hex id allocated by our server, nothing else.
The price is a different friend-add flow. Instead of typing in a phone number,
you exchange a QR code (or an invite link) with the person you want to talk to,
which carries the public half of a Diffie-Hellman handshake. That code never
touches our address book because there isn't one. The trade-off is real:
onboarding takes one extra step versus a phone-number lookup, and there's no
"find me by my email" path if you forget your friend's user id. We think the
ability to look someone up by their phone number is the original sin of modern
messaging — this is the smaller cost.
Is the code open source? Has the cryptography been audited?
Yes to open source. The reference Java client (which the desktop, Android and iOS
ports all derive from) lives at
github.com/Secchats-tech/ChatJavaUI,
including the wire-format model classes, the Diffie-Hellman + AES-256-GCM
encryption layer, and the polling state machine. The server's wire contract is
published as the JSON API reference — everything
another implementation needs to interoperate is documented, and other groups have
built independent backends from it (see our blog post
on one-shot server generation from the spec for an example).
On the audit question, we owe a more honest answer than most products give. The
cryptographic primitives we use are off-the-shelf and individually well-studied
(AES-256-GCM, ECDH, PBKDF2-HMAC-SHA256), but the protocol composition itself has
not been independently reviewed by a third-party security firm. We'd welcome
such a review and we'd publish the findings. In the meantime: the source is
small, the wire format is documented, and the protocol is approachable enough to
be reviewed by an interested reader in a long afternoon. If you find something
wrong with it, please open an issue on the GitHub repo above.
How is Secure Chats different from Signal, WhatsApp, Telegram, or iMessage?
The headline difference is the identifier. WhatsApp and Signal use your phone
number, iMessage uses your Apple ID, and Telegram uses both plus a username. We
use a random hex string allocated server-side, with no link to anything else
about you. That single change propagates through everything: there's no address
book lookup, no contact-discovery hash exchange, no "find me on this app via my
phone number" path, and no SIM-swap attack surface against your account.
Other apps each have real strengths we don't try to dispute. Signal's protocol is
independently audited and widely cryptanalysed; WhatsApp has billions of users
and the network effect that comes with that; iMessage is invisibly integrated
into the Apple device experience; Telegram has feature breadth (cloud sync,
public channels) that we don't aim for. What we offer specifically is the
smallest practical metadata footprint of any of them: no phone number stored, no
contact graph reconstructed, no push tokens registered with Apple or Google, no
cloud message backup, and a server-side database that surrenders close to
nothing under legal process (see the seizure question above). If that's the
trade you're looking for, we built this for you. If you need the things one of
the others does better, use that one — we won't be insulted.
What happens if I lose my phone or get a new one?
Two paths: with a backup you made in advance, or without.
With a backup. SecChats includes an on-device backup feature
— Settings → Back up essential data. It writes a single
.scb file containing your user id, your friends list, and your group
memberships, encrypted under a password you choose (minimum 12 characters,
AES-256-GCM with PBKDF2-HMAC-SHA256 at 600 000 iterations). Save the file
wherever you like — Files, AirDrop to another device, email to yourself, a
USB stick. Nothing goes to any cloud unless you personally put it there.
On the new phone, install SecChats, open the file, enter the password, and choose
Restore from backup. Your account, friends, and group keys land intact.
The format is byte-for-byte compatible across iOS and Android — back up on
one, restore on the other. Messages are not in the backup; they stay only on
whichever device they were originally delivered to.
Without a backup. You start over: new install, new
randomly-allocated user id, new keys, fresh slate. Your old conversations stay on
whichever devices they were already on (and become unreadable on the lost phone
unless someone has its passcode). To continue talking with the people you knew
before, each of them needs to add you again via a fresh QR-code exchange, which
establishes new Diffie-Hellman channels with your new identity.
We deliberately don't offer an automatic cloud backup. The reason every other
chat app has "restore from iCloud" or "restore from Google
Drive" is that they hold a credential that can decrypt your history off a
cloud blob — which means there's a credential to compel from Apple or
Google, and a backup whose contents inherit the cloud provider's threat model.
We don't want to be a party to that. The .scb file is entirely under
your control: your password, your storage location, no third party involved. If
you forget the password, no one — including us — can recover the file.
How do group chats work cryptographically?
A group has a single symmetric AES-256 key, generated by whoever creates the
group. To invite someone in, the creator (or a member with invite rights)
encrypts that group key using the existing one-to-one Diffie-Hellman channel they
already share with the invitee — the same channel that's used for direct
messages between them — and posts the encrypted bundle to the server. The
invitee's client unwraps it using its half of the DH secret, stores the group
key locally, and is now able to decrypt every group message addressed to that
group id. Group messages themselves are AES-256-GCM ciphertexts against that
shared key, posted under the group id; the server fans them out to everyone
who's polling that group.
Two honest caveats. First, the server can observe that user X polls group Y —
it has to, in order to route the wake-up — so the membership graph isn't
cryptographically hidden from the server even though the content is. Second,
removing a member doesn't automatically rotate the group key: a removed member
who kept a copy of the key could still decrypt new messages they later obtained
ciphertext for. Industry-standard fixes for both (sender keys with explicit
rotation, MLS-style epochs) are areas we'd like to evolve toward, and the source
is open if you want to help.
Why does the app feel slower at startup, or use more battery than WhatsApp?
Both effects are the direct consequence of not using push notifications (see the
first question above). When you open the app cold, the client has to open a fresh
long-poll connection to our server before it can show you new messages, because
nothing was woken up in the background to receive them on your behalf. On a
cold start that handshake adds maybe a second of latency before your inbox
refreshes — small in absolute terms, but noticeable compared to an app where
the OS already shoved the latest message into a banner before you tapped the icon.
The battery cost is similarly modest but real: maintaining one open TCP
connection per active conversation isn't free, and reconnecting every few minutes
burns slightly more radio time than passively waiting for an APNs/FCM wake-up.
Modern OS power-management actually handles long-poll connections reasonably
well, and our connection idle-timeout is tuned to balance battery against
latency, so the difference shouldn't be dramatic on any phone made in the last
few years. It is, however, the price of the privacy properties from the first
question on this page. If you don't want to pay that price, there are other
excellent chat apps you can use — this one is built for the people who do.