Getting started v0.0.2
Encrypted messaging with no accounts, no servers, no logs. Identity keys and end-to-end encryption from first launch. This page is the canonical reference for how it works and what its limits are.
Early release software. The crypto is real, but the implementation is young. Read the threat model before relying on TunnelTalk for anything that has consequences if it leaks.
Install
TunnelTalk is available as a Web app and an Android app. Both are free and require no account.
| Platform | Where to get it | Screenshot protection | Status |
|---|---|---|---|
| Web app | tunneltalkweb.pages.dev — open in any modern browser | Watermark only — cannot block OS screenshots | Live v0.0.2 |
| Android app | Download APK — enable "Install unknown apps" in Android settings | FLAG_SECURE blocks system screenshots and recents thumbnails | Live v0.0.2 |
The Android APK is a direct install (sideload). To install: download the APK, open it on your Android device, and confirm the installation. You may need to enable Install unknown apps for your browser in Android Settings → Apps.
First run
- Create your identity. On first launch you are prompted for a passphrase. This unlocks your identity keys — it never leaves the device. Pick something strong; we use Argon2id to stretch it but a weak passphrase reduces that protection.
- You get a fingerprint. The app generates an Ed25519 + X25519 keypair. The public-key fingerprint is your address. There is no username, no display name visible to anyone else unless you share it.
- Share your contact token. Tap Share in the sidebar. You get a compact
tt1:token (~90 characters) that fits in an SMS, plus a QR code. Send it to anyone you want to talk to. - Add a contact. Paste their
tt1:token (or scan their QR) to add them. Enter the nickname only you see. Once both of you have each other as contacts, open a DM — the app does a Noise IK handshake and you can start messaging. - Create a group. Click + next to Groups in the sidebar, name the group, and select contacts to invite. Invites are sent through your existing DM sessions — no group key is exposed in transit.
Identity
TunnelTalk has no accounts. Your identity is a keypair on your device, and your address is a public-key fingerprint. There is nothing to sign up for and nothing for an outside party to seize on your behalf.
Identity keys
On first launch the app generates two long-term keys using @noble/curves:
- Ed25519 for signing transport metadata.
- X25519 for key agreement during the Noise IK handshake.
The private halves are immediately encrypted with your passphrase under Argon2id (memory-hard, configurable time/memory cost) and stored encrypted in IndexedDB. The plaintext keys exist in memory only while the app is unlocked. Locking the app zeroes them immediately.
Fingerprint format
The fingerprint is BLAKE2b-160(edPub ‖ xPub) encoded as base32. It binds both public keys together so a peer cannot substitute a different X25519 key while reusing the same Ed25519 key. Fingerprints are shown in grouped segments for readability.
Contact token format
The compact share token is tt1:<base64url(edPub ‖ xPub)> — roughly 90 characters including the prefix. It fits in a standard SMS message alongside a short message. You can also share just the raw token for copy-paste.
Adding contacts
Contacts are public-key fingerprints with a nickname you assign locally. There is no central directory. Three ways to exchange them:
- Paste a
tt1:token — tap Paste code in the Add Contact modal. The app detects the token in any clipboard text, even inside a larger SMS body. - Scan QR code — tap Scan QR and point the camera at the other person's QR code. Auto-detected, no button press needed.
- Manual entry — paste the fingerprint, Ed25519 public key (base64), and X25519 public key (base64) separately. The app recomputes the fingerprint from the keys and rejects the contact if they do not match.
Verification ceremony
Once a Noise IK session is established, the app shows a safety code — a short number derived from both fingerprints using BLAKE2b. Read it aloud or compare side-by-side with your contact. If it matches on both sides, the session is authenticated end-to-end: no man-in-the-middle could produce the same code without knowing one of the secret keys.
Verification is a one-time ceremony per contact. After you mark a contact as verified, subsequent sessions still use the same keypair and the safety code stays consistent. You only need to re-verify if one of you generates a new identity.
Direct messages
Every direct message is end-to-end encrypted on the sender's device, sealed under forward-secret session keys from a Noise IK handshake, and never persisted on the relay. The plaintext exists only on the two endpoints.
Noise IK handshake
When you open a DM with a contact, TunnelTalk initiates a Noise_IK handshake using the pattern Noise_IK(25519, XChaCha20Poly1305, BLAKE2b). This produces two forward-secret session keys (one per direction) in a single round trip. Both sides must be online simultaneously for the handshake to complete. A spinner is shown until the session is ready; the composer is disabled until then.
Simultaneous initiation tie-break
If both sides open a DM at the same time and each sends a handshake initiation, the tie is broken by fingerprint lexicographic order. The peer with the lower fingerprint is treated as the canonical initiator; the other side discards its pending state and responds instead. This happens automatically with no user action required.
Message encryption
Each message is encrypted with XChaCha20-Poly1305:
- Nonce: 24-byte counter encoded in the last 8 bytes — strictly monotonic, replay-detected on receive.
- Additional data:
"TT-v1|{counter}"— binds the version and counter to the ciphertext. - Ciphertext envelope:
{ v: "TT-v1", n: counter, c: base64 }
Decryption rejects any message whose counter is ≤ the current receive watermark, preventing replay attacks.
Relay transport
The relay is a dumb WebSocket forwarder. It routes messages by the destination fingerprint field in the envelope header and nothing else. It never stores messages, never inspects payloads, and never logs content. Messages to offline peers are dropped with an undelivered notification to the sender.
Both parties must be online simultaneously. There is no store-and-forward. If your contact is offline when you send, the message is not delivered — you will see an undelivered indicator. Retry when they come back online.
Group chats
Groups support any number of members. All group messages are end-to-end encrypted with a shared symmetric key. The relay handles multicast — one send reaches all members without any member knowing who else is in the group from the relay's perspective.
Creating a group
- Click + next to "Groups" in the sidebar.
- Enter a group name and select contacts from your contact list.
- Click Create. The group is created immediately and you join the relay channel.
- Invites are sent to each selected contact through your existing DM sessions. This requires an established Noise IK session with each contact — if a session is not yet established, open a DM with that contact first.
Group key cryptography
Each group uses a single 32-byte random symmetric key generated at creation time:
- Messages are encrypted with XChaCha20-Poly1305 using a random 24-byte nonce per message.
- Random nonces (rather than per-sender counters) prevent nonce collision when multiple members share the same key without coordinating.
- Envelope format:
{ v: "TT-g0", nonce: base64, c: base64 }
Invite security
Group invites carry the group key and must be kept confidential. TunnelTalk sends invites as encrypted DMs — the invite payload is serialised as JSON, then encrypted with encryptMessage() over the existing Noise IK session. The relay sees only an opaque ciphertext envelope. The group key is never transmitted in plaintext.
If you want to invite a contact to a group but have no established DM session with them yet, open their DM first and wait for the Noise IK handshake to complete. Then create the group or add them from within the group.
Relay multicast
Groups use a subscription model on the relay:
- When you join a group (or reconnect), the client sends
{ type: "group-join", groupId }. - When you send a group message:
{ type: "group-msg", groupId, from: myFp, payload: encryptedEnvelope }. The relay broadcasts this to all subscribers. - The relay sees only the group ID (a random 32-hex string) and the ciphertext. It does not know who the members are or what is being said.
- Subscriptions are restored automatically when the WebSocket reconnects.
Persistence
The group list (names, keys, member lists) is persisted in IndexedDB, encrypted under a BLAKE2b-derived key from your identity secret key. Group messages are ephemeral — they live in memory only and are wiped on lock or reload.
Ephemeral storage
The on-disk surface of TunnelTalk is intentionally small. Everything else lives in RAM and disappears when you lock or close the app.
What stays on disk
Stored in IndexedDB, encrypted:
- Identity keys — encrypted with your passphrase via Argon2id. Plaintext only in memory while unlocked.
- Contact list — public-key fingerprints + nicknames, encrypted under a BLAKE2b-derived contact storage key.
- Group list — group names, keys, and member lists, encrypted under a BLAKE2b-derived groups storage key.
That is everything. No message content, no call logs, no ratchet state, no group message history is ever written to disk.
What lives in memory only
- All direct messages (current session only)
- All group messages (current session only)
- Noise IK session keys for each active conversation
- Plaintext identity private keys (Ed25519 seed + X25519 secret)
Disappearing messages
Each DM conversation has a configurable TTL: 5 min, 1 hour, 24 hours, or keep (∞). Messages older than the TTL are purged on a 30-second timer. The setting is local — it applies to your view only. Purge a conversation manually at any time with the trash icon in the conversation header.
Anti-leak posture
Encryption protects what is on the wire. Anti-leak posture is about what is on screen. Different platforms expose different OS facilities, and TunnelTalk uses what each one actually allows — not what we wish it allowed.
Per-platform capabilities
| Capability | Web app | Android app |
|---|---|---|
| Block OS screenshots | No — not possible in browsers | Yes — FLAG_SECURE |
| Block recents thumbnail | No | Yes — FLAG_SECURE |
| Watermark with viewer fingerprint | Yes | Yes |
| Blur on focus loss | Yes | Yes |
| Disable right-click / save | Yes | N/A |
| Disable text selection on messages | Yes | Yes |
| Block devtools | Deterrent only | N/A |
Web cannot prevent screenshots. Browsers do not expose an API to block OS-level screen capture. Watermarking deters leaks and identifies the source, but does not prevent capture. For screenshot-sensitive work, use the Android app.
Watermarking
The message area is overlaid with the viewer's fingerprint rendered as a faint repeated pattern. If a screenshot leaks, the fingerprint in the watermark identifies which device it came from — even if the screenshot is cropped or compressed. The watermark is rendered live and is never stored as a separate image file.
Panic wipe
The panic action (Settings → Panic Wipe) zeroes the in-memory state, overwrites the on-disk identity-keys blob, contacts blob, and groups blob in IndexedDB, and reloads the app to a clean first-run state.
- There is no undo.
- There is no cloud backup to restore from.
- After a panic wipe, your fingerprint is gone. Generate a new identity and share the new fingerprint with your contacts.
IndexedDB "clearing" is a logical delete — the underlying storage blocks may persist until the browser's garbage collector overwrites them. If you need cryptographic erasure guarantees, the safest option is full-device wipe. Panic wipe makes recovery computationally infeasible but is not a physical overwrite.
Threat model
A clear statement of what TunnelTalk defends against, what it does not defend against, and what it assumes about the device you use. Read this before deciding whether the tradeoffs match your risk.
What TunnelTalk defends against
- Content interception. The relay cannot read message content. Every payload is AEAD-sealed before it leaves your device. A compromised relay sees only opaque ciphertext and routing headers.
- Forward secrecy attacks. Noise IK produces per-session keys. Compromise of one session does not unlock prior sessions. Long-term identity keys never encrypt content directly.
- Identity spoofing. The Noise IK handshake mutually authenticates both sides using their long-term X25519 keys. The verification ceremony (safety code) catches man-in-the-middle attacks.
- Relay seizure. If the relay is seized or subpoenaed, the operator has routing metadata (fingerprint pairs, timestamps) but no message content. There is no message database to hand over.
- Screenshot by bystanders (Android only).
FLAG_SECUREblocks system screenshots, the app switcher thumbnail, and prevents screen-recording apps from capturing the content area.
What TunnelTalk does NOT defend against
- Routing metadata. The current relay sees which fingerprints communicate with each other and when. It does not see content, but traffic patterns are observable. I2P transport (roadmap) will address this.
- Endpoint compromise. If the device is rooted, key-logged, or recording the screen, no encrypted messenger can save you. Use a clean device for anything serious.
- Coerced unlock. If someone forces you to enter your passphrase, they have your messages for the duration of that session. Panic wipe before handing the device over.
- Recipient behaviour. If the person you are messaging chooses to screenshot, photograph, or transcribe the conversation, no protocol prevents it. Pick correspondents you trust.
- Web-tier screenshots. Browsers do not let apps block OS screen capture. The watermark identifies leakers but does not prevent capture.
- Side-channel emissions. Sound, RF, or electromagnetic side-channels are out of scope.
Assumptions
- You obtain the app from a trusted source (this website or the official APK link).
- The device's operating system is reasonably current and not actively compromised.
- Your passphrase is strong enough that Argon2id can hold off offline brute-force for the time it takes to revoke the identity.
- The relay operator does not actively correlate traffic patterns over long periods (this is mitigated by I2P transport, which is on the roadmap).
FAQ
Why no phone number?
Phone numbers are an identity record an adversary can subpoena, SIM-swap, or bind to a real-world person without your consent. TunnelTalk's identity is something you generate locally and share only with people you trust. Removing phone numbers is the entire point.
How do I add someone as a contact?
Ask them to tap Share and send you their tt1: token. It is about 90 characters — fits in an SMS. Open TunnelTalk, tap + Contact, paste the token (or scan their QR code), and add a nickname. They do the same for you. Once both sides have each other as contacts and are online at the same time, the Noise IK handshake completes automatically.
Why must both people be online at the same time?
The relay does not store messages. It is a dumb forwarder — if the recipient is offline, the message is dropped. This is a deliberate tradeoff: no storage on the relay means nothing to seize or subpoena. If your contact is offline, try again when they are online. Store-and-forward with strong privacy guarantees is on the roadmap.
How is this different from Signal?
Signal is excellent at content encryption but uses a centralised service tied to a phone number. That service knows who is talking to whom (metadata), even though it does not know what is being said. TunnelTalk removes both the central service and the phone-number identity at the cost of convenience — no push notifications, no automatic contact discovery, and no offline delivery.
Can the developer read my messages?
No. The relay is a dumb forwarder that cannot decrypt anything. Even if the developer organisation were compromised, there is no plaintext message data anywhere on infrastructure we operate. Keys never leave your device.
What happens if I lose my device?
Your identity is gone — which also means nobody can impersonate you with that key. Generate a new identity on a new device and share the new fingerprint with your contacts. There is no cloud backup and no key escrow. That is a feature.
Can I use TunnelTalk on multiple devices?
Not in the current release. Each device has its own independent identity. Multi-device support (same identity, multiple devices) is on the roadmap.
Why does the relay see my routing metadata?
The current release uses a WebSocket relay for message delivery. The relay sees which fingerprints communicate with each other and when — it cannot see message content. Full I2P transport, which hides who is talking to whom from even the relay, is on the roadmap. We document this limitation instead of hiding it.
Is the source code open?
The protocol and cryptographic primitives are documented here. The client implementation is in active development. Source release is planned once the API surface stabilises and an external review pass is complete. The design assumes the code is readable — security does not depend on source secrecy.
Roadmap
What is shipped, what is next, and what is coming later. Dates are not published until the work is committed.
Shipped — v0.0.2 (current)
- Identity keys (Ed25519 + X25519), Argon2id-encrypted at rest
- Noise IK handshake for DMs — mutual auth + forward secrecy
- XChaCha20-Poly1305 message encryption with counter nonces
- Group chats with shared symmetric key + random nonces per message
- Secure group invites over existing DM sessions
- Compact
tt1:contact token for SMS/email sharing - Built-in QR scanner for contact exchange
- Disappearing messages (per-conversation TTL)
- Safety code verification ceremony
- Android app with
FLAG_SECUREscreenshot blocking - Web app (tunneltalkweb.pages.dev)
Up next
- Store-and-forward for offline delivery (relay-side, encrypted, TTL-bounded)
- Push notifications for Android
- Group key rotation when members are added or removed
- Multi-device support (same identity, multiple devices)
- Double Ratchet upgrade over Noise IK for post-compromise security
Later
- I2P transport — full network anonymity hiding who is talking to whom
- Voice messages (Opus, ephemeral)
- Voice and video calls (WebRTC, SRTP keys from Noise session)
- Public source release after external security review
We ship honestly. If a feature is not listed as shipped, it is not available yet, regardless of what any marketing copy may imply. This roadmap is the ground truth.