This document describes the encryption flow in Dialtone, what is encrypted, what is not, and why.
- Protect message content and channel names from the server and network observers.
- Allow multi-device access by securely sharing symmetric keys via public key encryption.
- Accept that compromised client endpoints can read decrypted content.
-
Device key pair (asymmetric)
- Each device generates a long-term key pair locally.
- Private key is stored locally in the encrypted keystore.
- Public key is sent to the server for key sharing.
-
Channel key (symmetric)
- One per channel.
- Encrypts message bodies and channel metadata (like channel names).
-
Directory key (symmetric)
- Encrypts directory/profile data (profile display names) stored server-side.
-
Key envelopes
- A symmetric key encrypted for a specific device using public key crypto.
- Only the target device can decrypt it with its private key.
-
Username
- Used for login/identity lookup.
- Sent in plaintext during login/register and stored only as a peppered hash.
-
Profile display name
- Optional, user-visible name stored in the directory.
- Encrypted with the directory key.
flowchart TD
A[User writes message] --> B[Client encrypts with channel key]
B --> C[Ciphertext sent to server]
C --> D[Server stores and relays ciphertext]
D --> E[Recipient client receives ciphertext]
E --> F[Client decrypts with channel key]
F --> G{Another message?}
G -->|Yes| A
G -->|No| H[Wait for next message]
sequenceDiagram
participant DeviceA as Device A
participant Server
participant DeviceB as Device B
DeviceA->>Server: Upload public key
DeviceB->>Server: Upload public key
Note over DeviceA: Create channel key
DeviceA->>Server: Create channel (encrypted name)
Note over DeviceA: Build key envelopes
DeviceA->>Server: Upload key envelopes
DeviceB->>Server: Request key envelope
Server->>DeviceB: Encrypted envelope
Note over DeviceB: Decrypt envelope (private key)
The client stores sensitive materials (device private key, channel keys, directory key) locally. The keystore is encrypted with:
- scrypt KDF
- AES-256-GCM
A passphrase is required to decrypt the keystore. If the passphrase is wrong, content remains encrypted and keys cannot be used.
- Message bodies (channel key)
- Channel names (channel key)
- Sender display names in messages (channel key)
- Profile display names (directory key)
- Stored device keys and channel/directory keys in local keystore
-
User IDs, device IDs, channel IDs
- Needed for routing, indexing, and access control.
- Device ID is a server-generated identifier for a specific client installation/device. It is not a cryptographic key or a public key.
-
Timestamps and message metadata
- Needed for ordering and display.
-
Public keys
- Must be public to enable key sharing.
-
Usernames
- Sent in plaintext during login/register so the server can authenticate.
- Stored only as a peppered hash (no plaintext usernames in the database).
-
Network metadata
- Standard transport metadata (IP, timing) is outside app-level encryption scope.
- Sender obtains channel key (local keystore or key envelope).
- Client encrypts message body with the channel key.
- Client encrypts sender display name with the channel key.
- Client sends ciphertext to the server.
- Receiver decrypts ciphertext using the same channel key.
- Message bodies are encrypted client-side with the channel key before upload.
- Sender display names in messages are encrypted client-side with the channel key.
- The server stores and returns ciphertext for message bodies and sender names.
- Message IDs, channel IDs, sender IDs, and timestamps are stored in plaintext for routing, indexing, and ordering.
- Device obtains directory key (local keystore or key envelope).
- Client encrypts profile display name with directory key.
- Server stores encrypted profile data.
- Other devices decrypt profile fields using directory key.
- Missing channel key: client shows "" placeholders.
- Missing or invalid envelope: client cannot decrypt until a valid envelope is shared.
- Wrong keystore passphrase: keys are inaccessible, decryption fails.
- Protected against server-side inspection of message content and channel metadata.
- Not protected against compromised devices or malware on the client.
- Key sharing relies on trusted devices correctly distributing envelopes.
Dialtone uses symmetric encryption for message bodies and channel names, and public key encryption to share those symmetric keys across devices. The server never sees plaintext message content or channel names, but it can see routing metadata required for the system to function. Usernames are sent in plaintext during auth but stored only as a peppered hash.