who holds the keys.
Everything you send is locked on your device first. It stays locked on the way and on disk. Each server keeps the keys for its own conversations. So you choose who to trust by choosing where you talk.
four things worth knowing
- locked first
- Messages and files are encrypted on your device before anything leaves it. Voice and screen shares are too.
- keys stay put
- A server makes each channel's key and seals it with its own identity. A copied database is useless without that identity file.
- the operator can read
- Whoever runs a server can read its channels. On a community server that's the owner. For direct messages and calls it's the hub. Run your own and it's only you.
- servers get checked
- Your app remembers each server's identity the first time it connects. It warns you if that identity ever changes.
what happens when you hit send.
- you get an identity
On first run your device makes two key pairs. Ed25519 signs and X25519 agrees keys. Your account keeps a copy sealed with your password so you can sign in on another device.
- the server keys the channel
Every channel gets a random 32-byte key. The server stores it sealed to its own identity. Each member gets a copy sealed just for them.
- the message is locked and signed
XChaCha20-Poly1305 encrypts the message. It's tied to its channel and sender and ID. Move it somewhere else and it won't open. The sender signs it as well.
- voice goes in 10 ms slices
Each slice of audio is encrypted on its own. A 28-byte header lets the server route it. A slice that shows up twice is dropped.
- streams are encrypted per frame
Screen shares go through a media relay that ships with the server. Every video frame is encrypted with the channel's media key.
- keys change when people leave
When someone leaves or gets removed the server makes a fresh channel key. New messages use it. The person who left never gets it.
standard parts. nothing homemade.
| job | used for it |
|---|---|
| Encrypting messages and media | XChaCha20-Poly1305 with a 24-byte nonce and a 16-byte tag |
| Sealing a key for one person | Sealed box over X25519 and XSalsa20-Poly1305 |
| Identity | Ed25519 for signatures and X25519 for key agreement |
| Turning a password into a key | Argon2id with 64 MiB of memory and 3 passes on 1 lane. 32-byte output. |
| Proving a password without sending it | HMAC-SHA256 over a nonce the server picks |
| Server fingerprints | BLAKE2b-256 shown as 8 groups of 4 hex characters |
All of it comes from libsodium. It's bundled with the app and the server. Nothing is fetched from anywhere else.
how it's checked
- test vectors
- One file pins the exact bytes for every operation. It also has broken inputs that must fail. The server and the browser app both test against it.
- tampering
- Change one byte of a message or its nonce and decryption refuses. Those cases run on every change.
- specs
- The wire protocol and the crypto design are written down and versioned. Read them here.
No outside audit yet. Veiled is alpha software. Treat it that way until someone independent has reviewed it.