Security, step by step

How Wasla works

Seven diagrams in the order you meet them: setting up, adding someone, chatting, sending while they’re offline, calling, groups, and keeping your chats. For the plain-language version, see How Wasla keeps you safe.

1. Setting up: your account lives on your phone

No phone number, no server account. Your keys are made on your phone and never leave it.

Identity from a BIP-39 phrase (Ed25519); keys in the Keychain / Keystore; database with SQLCipher; media with AES-256-GCM.

1Your account is made on your phone

On first launch, your phone picks 12 random words. Everything else is calculated from them, on the phone.

12 random wordsyour recovery phrase
→
SeedBIP-39
→
Identity keyEd25519, private, stays on the phone
→
Your Wasla IDthe public half, safe to share
No phone number, email or password is needed, and the server never creates an account for you. Write the 12 words down: they are the only way back in.

2Keys in secure hardware

Keychain (iPhone) · Keystore (Android)
Identity keywho you are
Storage keyrandom, 256-bit
Other apps can’t read them, and they never go into a backup. A new phone gets your identity back only from your 12 words.

3Three layers of encryption

Whole databaseSQLCipher, key from the storage key
Message text, captions, quotesencrypted again, field by field
Photos and voice notesAES-256-GCM, done natively

4Locks and privacy screens

  • App lock with Face ID or fingerprint
  • Chats hidden in the app switcher
  • Message previews can be hidden from the lock screen
  • Recovery phrase copied for a short time only
  • iPhone: the database is kept out of device backups

5Checks before you send

Before a message is encrypted, Wasla looks for things you might regret sharing, on the phone only.

recovery phrasescard numbersIBANspasswordsone-time codes
Nothing is uploaded and no AI service is involved.

2. Adding people

Nobody can reach you until you say yes, and strangers can’t even see you exist.

Signed requests (Ed25519), names sealed with nacl.box, “Find me” stored as HMAC-SHA256 fingerprints.

1Your ID is your public key

Share it as an invite link or a QR code. The part after # never reaches any server.

https://api.waslachat.app/add#id=…&n=…&k=…
invite linkQR codeemail (if findable)

2A signed, sealed request

The request is signed by the sender. Their name inside is sealed so only you can read it, and padded so its length gives nothing away.

Ahmed
→
signed requestname sealed · valid 7 days
→
Sara
The relay can’t fake a request, change the name, or turn a “no” into a “yes”.

3Nothing until you accept

Requestno messages, no calls
→
Acceptednow you can talk
“Online” is only shown between people who added each other. A stranger can’t tell whether an ID exists.

4“Find me” by email (optional)

You prove the email with a code. The server keeps a fingerprint and a masked hint, never the address.

stored = HMAC-SHA256(secret server key, email)
shown = "a***@gmail.com"
The code itself is stored hashed for 10 minutes only.

5Looking someone up

someone types the email
→
same fingerprintcomputed by the server
→
Wasla IDonly if findable
Lookups are limited per person, per network and per day, so nobody can scan the list.

6Verify in person

Both phones show the same 60-digit safety number, made from both IDs. Compare it face to face or on a call.

31415 92653 58979
32384 62643 38327
95028 84197 16939
93751 05820 97494
=
31415 92653 58979
32384 62643 38327
95028 84197 16939
93751 05820 97494
If they match, nobody is sitting between you.

3. Chatting: end-to-end encryption

Two phones. A secret that is never sent. Only Sara’s phone can read what Ahmed writes.

Ahmed and Sara are an example. Built with Ed25519, X25519, HKDF-SHA256, an HMAC ratchet and XSalsa20-Poly1305.

1Each phone makes a fresh key pair

Every time two phones start talking, each makes a brand-new temporary key pair, kept only in memory.

Ahmed’s phone
Private key anever leaves memoryPublic key Ashared next
Sara’s phone
Private key bnever leaves memoryPublic key Bshared next
Their permanent identity keys (made from the 12 words) stay in the Keychain / Keystore. Only temporary keys are used for messages.

2Signed, then exchanged

Each phone signs its temporary public key with its permanent identity key. The signed note says who it’s from, who it’s for, when, and a random number.

Ahmed
signed note
Relaypasses it on
signed note
Sara
sign(identity key, "wasla-kx-v2 | from | to | A | time | nonce")
Sara checks the signature against Ahmed’s Wasla ID (the ID is his public key), that it’s under 5 minutes old and never seen before. A swapped key fails.

3Both phones compute the same secret

With X25519, each phone mixes its own private key with the other’s public key. They get the same result. It is never sent.

X25519(a, B)on Ahmed’s phone
X25519(b, A)on Sara’s phone
↓ ↓
Same shared secret Snever transmitted
Someone who sees A and B can’t work out S. That’s the maths of X25519.

4Two one-way chains

The secret goes through HKDF together with both IDs and both public keys. Out come two chain keys, one for each direction.

S
→
HKDF-SHA256“wasla-session-v2” · both IDs · A · B
↓ 96 bytes
Ahmed → Sarachain key, 32 bytes
Sara → Ahmedchain key, 32 bytes
S is wiped from memory straight after.

5A new key for every message

Each chain is a ratchet that only turns forward. Every message gets its own key, which is deleted after use.

Chain key CKn
↓HMAC-SHA256
Message keyHMAC(CK, 0x01)
used once, then wiped
Next chain keyHMAC(CK, 0x02)
replaces the old one
Going back is impossible, so a key stolen today can’t open earlier messages.

6Locked and tamper-sealed

The message is encrypted with XSalsa20 and sealed with Poly1305. Any change on the way breaks the seal.

“Hello Sara”
↓
XSalsa20 encrypt · Poly1305 sealwith this message’s key
↓
ciphertext+ tag + counter
  1. Sara’s phone makes the same message key from its copy of the chain.
  2. It checks the seal first.
  3. Only then does it decrypt. A broken seal means the message is thrown away.

7No replays, any order

Every message carries a counter. Copies are refused, and late messages still open.

#1#3#2#2
#2 arrives lateopened with a saved key
#2 againrejected as a replay
Up to 1,000 skipped messages can still be opened later; their keys are kept only until then.

8Phone to phone, not through a server

Once the handshake is done, sealed messages travel over a direct encrypted connection (WebRTC) between the two phones.

Ahmed
sealed messages
Sara
Relaynot on this path
receiptstypingstatusesname & photocall setup
The relay still knows that two Wasla IDs connected, and when. It never sees what they say.

9Session ends, keys vanish

Sessions live only in memory. When Wasla closes or the connection drops, all temporary keys are wiped. Next time, a new handshake starts.

Session opentemporary keys in use
↓
App closed / offline
↓
All keys wipednothing to steal later
A phone backup never contains message keys, and someone who later steals the 12 words can’t open past conversations they recorded.
ConfidentialOnly the two phones can read the message.
AuthenticSigned keys prove who you’re talking to.
Tamper-proofAny change breaks the seal.
Forward secretOld messages stay safe if a key leaks.
Server-blindThe relay never holds a key.

4. When your friend’s app is closed

Every way a message reaches a phone that isn’t open, and none of them lets anyone read it or keeps it on a server.

Sealed pushes and fetched photos use X25519, HKDF-SHA256, ChaCha20-Poly1305 and an Ed25519 signature, the same tools Apple’s CryptoKit has built in.

1Which way does it go?

Sara’s app open?
yes
Phone to phonesee Messages
no ↓
Short text?
yes
Sealed pushpanel 2
no ↓
Photo, voice note or long text?
yes
Preview in the push, the rest fetched on arrivalpanel 4
Ahmed offline too ↓
Waits on Ahmed’s phonepanel 5

2Sealed inside a notification

Short texts (about 1,500 Latin or 800 Arabic characters) ride inside the push, sealed to Sara’s delivery key.

eph = new X25519 key
key = HKDF(X25519(eph, Sara), "wasla-push-v1")
box = ChaCha20-Poly1305(key, message + Ahmed’s signature)
A fresh key is made for every push, and Ahmed’s signature inside proves the message is really his.
Sara’s delivery key is replaced every week and old ones are deleted two weeks later, so a key stolen one day can’t open notifications from long before.

3Apple and Google only carry it

Ahmed
Apple / Googlepush service
Sara
  • That a notification arrived
  • Its size
  • Who sent it
  • What it says
iPhone opens it in a small extension that has the key; Android opens it in Wasla. Message previews can be turned off.

4Fetched on arrival

Ahmed sends a photo and Sara’s app is closed. The push brings a blurred preview. In the same moment, Sara’s phone opens a short, direct connection to Ahmed’s phone, which is most likely still in Wasla, and the photo comes straight from his phone, sealed to Sara. The relay only introduces the two phones; the photo never passes through it.

Ahmedstill in Wasla
Direct connectionphoto goes phone to phone
Saraapp closed
  1. Preview. A sealed push reaches Sara’s phone: who it’s from, and a tiny blurred version of the photo.
  2. Introduce. Sara’s phone sends Ahmed’s phone a connection offer for “photo 42” through the relay, which checks they’re contacts. Ahmed’s phone answers the same way.
  3. Connect. The two phones open a direct, encrypted connection to each other.
  4. Seal and send. Ahmed’s phone checks it’s really his photo to Sara, seals it to Sara’s key with his signature inside, and sends it straight to her phone. Then the connection closes.
  5. Open. Sara’s phone checks Ahmed’s signature and opens it. The real photo appears in the notification, and is in the chat when she opens Wasla.
On iPhone, Wasla’s small notification extension does this on its own within a few seconds, with a fetch ticket that only allows this one thing. If the two phones can’t connect directly (some strict networks), the photo isn’t sent another way: it waits on Ahmed’s phone until both are online (panel 5).

5If Ahmed is offline too

If Ahmed sent it and closed Wasla straight away, his phone can’t answer. The photo stays on his phone, encrypted, until both phones are online, and then goes phone to phone.

Ahmedholds it
→
Wake-up pushno content, no sender
→
Saragets it when both are online
Nothing waits on any server. Sara sees the preview straight away; the full photo follows when both phones are reachable.
While Sara’s phone is collecting it, Ahmed’s chat says “Delivering… keep Wasla open a moment”. If he leaves Wasla anyway, his iPhone asks for a few extra seconds to finish.

6What the server keeps

Messages, photos, voice notesnothing
A fetched photonever passes through it
“Someone has a message for you” marker24 h, no content
iPhone fetch ticketa fingerprint only
“Received” notes (ticks)passed on sealed, not kept

7Grey ticks and blue ticks

Ticks are receipts from Sara’s phone, encrypted like messages. They don’t need both apps open at the same time.

Ahmedsees the ticks
sealed “received” / “read”
Saraapp closed or open
  1. Received, at once. When Ahmed’s message reaches Sara’s phone by notification, her phone sends a short “received” note back through the relay, sealed: the relay can’t read it or see which message it’s about. Ahmed sees two grey ticks within seconds.
  2. Inside every reply. Each message Sara sends carries her latest receipts inside its encrypted content. When she replies, even by notification, Ahmed’s ticks catch up.
  3. Read. Blue ticks only if Sara has read receipts on; a reply never turns them blue otherwise.
Nobody can fake a tick: Sara’s app signs her notes, and her iPhone’s notification extension, which never holds her identity key, proves them with a key only her phone and Ahmed’s can compute.

5. Calling: voice, video and screen sharing

The server rings the phone. The call itself goes straight between the two phones.

Signalling inside the end-to-end channel; voice, video and screen with WebRTC DTLS-SRTP; addresses from public STUN. No TURN relay.

1Ringing

The invite travels inside the encrypted chat. If Sara’s phone is asleep, the relay wakes it with a sealed push.

Ahmed
Relaywake-up only
Sararings
iPhone: CallKit screenAndroid: full-screen call

2Nothing on until Accept

Ringingcamera off · mic off
→
Acceptthen camera & mic
Permissions are checked before a call rings or is answered, so a call never fails silently.

3Finding a path

Each phone asks a public address service (STUN) what its own internet address is, then shares the answer inside the encrypted chat.

Phone
↔
STUN“what’s my address?”
STUN sees an address request, never the call.

4Agreeing the call key

The call setup, including each phone’s DTLS fingerprint, travels only inside the end-to-end channel. The phones then run a DTLS handshake to make the call keys (SRTP).

setup + fingerprintsend-to-end encrypted
→
DTLS handshakecall keys made on the phones
No server can slip in a fingerprint of its own, so nobody can sit in the middle.

5Voice and video, phone to phone

Ahmed
SRTP, encrypted
Sara
video ≤ 800 kbpsquality barsno server in between
Without a relay server, a few strict networks can’t connect phone to phone. Wasla shows “Couldn’t connect” rather than routing your call through a server.

6During the call

  • Network changes (Wi-Fi ↔ mobile): it reconnects for up to 45 seconds
  • Voice → video: renegotiated inside the encrypted chat
  • A phone call comes in: both sides see “on hold”
  • Another Wasla call: a quiet “call waiting” banner
  • Leave the call screen or the app: the call keeps going in a floating window
  • Call ends: keys discarded, a short tone plays

7Sharing your screen

Every call reserves a second, empty video channel. Sharing puts your screen into it, protected by the same call keys, so it goes straight to the other phone and your camera keeps its own channel, on or off.

You tap Shareand confirm on the phone’s own prompt
→
Screen channelencrypted, phone to phone
→
Sara sees your screenyour camera as a small tile
→
Stopbanner, button or notification
iPhone: a small Wasla extension captures the screen and passes it to Wasla inside the phone, through a private shared folder. A banner stays up while you share; notifications that pop up are visible too, so use Do Not Disturb.

6. Groups: a group that lives only on the members’ phones

No group exists on the server. Membership is a signed record every phone checks for itself; every message is signed by its author.

Ed25519 signatures on every change and message; a hash chain of changes; SHA-256 of each file; the same end-to-end channels and sealed pushes as one-to-one chats.

1Membership is a chain of signed changes

1 createsigned by Ahmed
→
2 add Sarasigned by Ahmed
→
3 Sara joinsSara’s own signed “yes”
→
4 renamesigned by an admin
Each change names the one before it. Every phone folds the chain the same way, so everyone agrees who is in, and only admins can write to it. Nobody is in a group without their own signed “yes”.

2Every message is signed by its author

group · id · author · time · text
→
Ed25519author’s identity key
→
signed message
Any member can hand a message on to one who was away; it still carries its author’s signature, so it can’t be changed, forged or moved to another group. A photo’s fingerprint (SHA-256) is signed, so the file can come from anyone who has it.

3Sent to each member, phone to phone

Ahmed
one sealed copy per member
Sara, Omar…
The relay connects members’ phones exactly as it connects contacts; it never learns they form a group. A member who isn’t connected gets one sealed notification, like a one-to-one message.

4Reactions, edits and deletions are signed too

A reaction, an edit or “delete for everyone” is a small signed message naming the one it changes. Each phone applies it only if the signature is the right person’s: anyone may react, only the author may edit or delete. They’re never pushed as notifications; they arrive when the phones next connect.

5Strangers stay marked

A member who isn’t your contact is shown as ~ their name, never as a name from your contacts, so nobody can pass for someone you know. Their phone may only send group frames to yours; statuses, calls and one-to-one messages stay contacts-only.

6Catching up

  1. Two members’ phones connect and swap what they have: the chain version and recent message IDs
  2. Each asks for what it misses, and sends what the other lacks
  3. If two admins changed the group at the same moment, the same rule on every phone picks a winner and the other change is made again

7. Keeping your chats: backups and new phones

Your 12 words are the only key. Apple and Google store boxes they can’t open.

HKDF-SHA256 from the recovery phrase; XSalsa20-Poly1305; HMAC file names; transfers sealed with a key that only travels through the camera.

1A backup key from your 12 words

12 words
→
seed
→
HKDF“wasla-backup-v1”
content keyencrypts
name keyscrambles file names
Separate from your identity key: a backup key can’t sign or read messages.

2Sealed on the phone

chats, photos
→
padded to size stepssizes reveal little
→
XSalsa20-Poly1305
Only sealed files leave the phone.

3Stored where you choose

Your phone
→
Google Drive hidden app folder
iCloudfile name: a7f3c9e1….bin
Wasla only asks Google for its own hidden folder, not your other files.

4Restoring

  1. Install Wasla, choose “I have a recovery phrase”
  2. The 12 words rebuild your identity and backup keys
  3. Wasla downloads the sealed files, checks each seal, then opens them

5Moving phones directly

The new phone shows a QR code holding a random 256-bit key. It travels only through the camera.

New phoneshows QR
←←
Old phonescans it
QR = wasla://transfer#r=room&k=secret

6The transfer itself

Old
sealed, numbered messages
New
Relaypairs the room only
Each message is sealed with keys from the QR secret and numbered, so the relay can’t read, change, replay or reorder anything.