BitDM: no account, no phone number. End-to-end encrypted, works over Bluetooth without internet. Free and open source (AGPL-3.0), for Android, Windows, Linux and the browser.
SocialDart · PythonGitHub @Henner4746OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
End-to-end encrypted messenger without phone number, e-mail or username — your address is your public key. Signal protocol, Bluetooth offline mode, Tor. Android, Windows, Linux, Web. AGPL-3.0
Loading the full README.
Read the full README ↗This page in German.
An encrypted messenger with no phone number, no username, and no account. Your address is your public key.
| Platform | State |
|---|---|
| Android 9+ | released, signed APK |
| Windows x64 | released, unsigned installer and zip |
| Linux | released, tar.gz; tested in a container under Xvfb, not yet on a real desktop |
| Web | runs at bitdm.net/app, limited |
Most messengers ask for your number first. BitDM asks for nothing. On first launch it generates a key pair; the 56-character address it shows you is the public half of it.
That has a consequence which is easy to miss and hard to overstate: no server can hand you the wrong key. To do that it would have to change the address, and you already have the address. There is no directory to poison, because there is no directory.
tayn-bret-xl2d-i6f6-i5h4-cleu-salt-5mr3-ed3a-m3yo-bafm-qwqf-wdwo-rd2p
└─ base32( pubkey[32] ‖ sha256(pubkey)[:3] ): 35 bytes, exactly 56 characters
Three checksum bytes rather than two, for a reason worth one line: 35 bytes
divide evenly into base32, so there is never a = to strip and re-append. The
side effect is 24 bits of typo detection instead of 16.
[!WARNING] This software has not been independently audited. It sends real messages and the reasoning behind each part is written down, but no outside party has reviewed the result. Read Known gaps before you rely on it. If your safety depends on the encryption, for example as a journalist or under surveillance, use Signal until BitDM has had an independent audit.
There are three paths, and which one a message takes is decided in exactly one
place: app/lib/core/nah/wegwahl.dart. Never two paths for the same message:
that would be two encryptions of one text, and two key chains side by side in
the Double Ratchet.
flowchart TD
M["Alice sends"] --> T{"Text or attachment?"}
T -->|text| P{"Nearby-only<br/>switch on?"}
P -->|"yes: never touch a server"| BLE["Bluetooth LE<br/>no Wi-Fi, no mobile data,<br/>no data centre"]
P -->|no| RCH{"Relay reachable?"}
RCH -->|yes| RLY["Relay<br/>encrypted envelope over TLS"]
RCH -->|"no, nearby enabled"| BLE
RCH -->|"no, nearby off"| WAIT["Stays queued.<br/>Queued, not failed."]
T -->|attachment| SPLIT["Split into 32 MiB chunks,<br/>one random AES-GCM key each"]
SPLIT --> BLOB["Blob store<br/>sees ciphertext, size, time"]
SPLIT --> RCP["Recipe holding the keys:<br/>an ordinary Signal message"]
RCP --> RLY
RLY --> BOB["Bob"]
BLE --> BOB
BLOB --> BOB
The attachment split is not caution for its own sake. AES-GCM is broken, not merely weakened, the moment one key meets one nonce twice; a fresh random key per chunk removes the counter that would otherwise have to survive every resume and abort. The chunk number travels in the authenticated data, so a store that swaps chunk 3 for chunk 5 produces a decryption failure instead of a quietly wrong file.
1 · The address is the key. No registration, no lookup, no trust in a directory. You verify a contact by comparing 56 characters, not by trusting that a server matched a phone number to a key.
2 · It works with no server at all. Two phones next to each other exchange
messages over Bluetooth LE. Measured on two devices with mobile data switched
off: 325 bytes in 1.35 seconds, the one measurement on this page for which
no log exists in the repository. The radio underneath was measured separately on
the same two phones and is written down: 120 ms to find the peer, 700 bytes in
202 ms over GATT, and no system dialog at any point
(docs/NAHBEREICH.md).
To find each other without broadcasting who they are, devices emit beacons instead of addresses: six bytes per contact, derived from the shared secret and the current 15-minute window.
beacon = HMAC-SHA256( shared_secret, "bitdm-nearby-v1" ‖ sender_pubkey ‖ be64(window) )[:6]
shared_secret = X25519( own_private_identity, their_public_identity )
Hold the secret and you recognise your contact. Don't, and you see six bytes of noise that change every quarter hour. The sender's own key is inside the input, so what Alice emits is not what Bob emits; a recorded beacon cannot be replayed to impersonate the other side. Three windows are checked when scanning, not one, because two phones never share a clock and a device that vanishes for a minute every quarter hour arrives at the user as "it works sometimes".
3 · You can run the whole thing yourself. The relay is one Python file and a systemd unit. One command sets it up:
curl -fsSL https://bitdm.net/install.sh | sudo bash
Piping an unread script into a shell is a question of trust, and the right answer to it is suspicion. Download it, read it, then run it. Or see every step first without changing anything:
curl -fsSL https://bitdm.net/install.sh | sudo bash -s -- --dry-run
This is the beginning of the README. Read the rest at the original. Read the full README ↗