You don’t implement this cryptography yourself. The Chat XDK handles it. This page is for understanding, not an API checklist.
The big picture
X Chat uses a layered encryption system where:- Messages are encrypted with a conversation key (fast symmetric encryption)
- Conversation keys are encrypted to each participant using their identity public key (asymmetric key exchange)
- Messages are signed so recipients can verify who sent them and that nothing was altered
Key types explained
X Chat uses three kinds of key material, each with a specific purpose.1. Identity keypair
Purpose: Securely exchange conversation keys between users
When someone adds you to a conversation, they encrypt the conversation key using your identity public key. Only your identity private key can decrypt it.
Public halves are registered and discovered through the platform’s public-key APIs (see Encryption keys under API reference). Private halves stay in the Chat XDK (for example via Juicebox or a carefully protected key blob).
2. Signing keypair
Purpose: Prove that you authored a message
When you send a message, it is signed with your signing private key. Recipients verify using your signing public key (also published through the public-key APIs). The Chat XDK signs as part of encrypting a message and can verify on decrypt when you supply the sender’s public key material.
3. Conversation key
Purpose: Encrypt and decrypt messages (and media) within a specific conversation
Conversation keys are generated when a conversation is set up or when keys rotate. Each participant gets an encrypted copy of the key, produced with their identity public key. After you decrypt your copy once, you keep the raw conversation key and use it for fast message (and media) encryption. Setting up those copies for a conversation is done through the Chat XDK together with conversation key endpoints—walked through in Getting Started.
How encryption works (conceptually)
Sending a message
1
Start with plaintext
You type: “Hello, how are you?”
2
Get the conversation key
Your app uses the raw conversation key for this chat (from setup or from an earlier key-distribution event), for the right key version.
3
Encrypt the message
The Chat XDK encrypts your message with the conversation key. The result is ciphertext that is useless without that key.
4
Sign the message
The Chat XDK signs the encrypted payload with your signing private key, proving you authored this exact content.
5
Send to X
Your app sends the encrypted payload and signature to X through the Chat API send message endpoint. X stores and delivers bytes it cannot read as plaintext.
Receiving a message
1
Receive encrypted data
Your app receives ciphertext from X—via webhooks or an activity stream, or by reading conversation events for history.
2
Get the conversation key
Use your cached raw key, or obtain it by decrypting your copy from a key-distribution (key change) event if this is new or rotated.
3
Verify the signature
The Chat XDK checks the signature using the sender’s signing public key (and related identity binding), so you know who sent it and that it was not modified.
4
Decrypt the message
The Chat XDK decrypts with the conversation key. You can now read: “Hello, how are you?”
Key distribution explained
A central challenge in end-to-end encryption is key distribution: how participants get the conversation key without X (or an observer) seeing that key in the clear.Initial key setup
When a conversation is prepared for messaging:- The Chat XDK generates a random conversation key
- The Chat XDK encrypts that key to each participant’s identity public key
- Your app publishes those encrypted copies through X’s Chat APIs
- Each participant decrypts their copy with their identity private key (in the Chat XDK)
Key change events
When the conversation key rotates (for example when membership changes), participants receive a key change event with new encrypted copies for each member. Your app should:- Notice key-change material on live events or in conversation history
- Decrypt and store the new conversation key (and version)
- Use the latest version for subsequent sends
Juicebox: distributed key storage
Your private identity and signing keys must be stored carefully. X Chat integrates Juicebox so keys can be recovered with a PIN across devices without giving any single server the full secret.The problem with traditional key storage
How Juicebox solves it
Juicebox combines secret sharing with PIN protection:- Private keys are split into shares
- Shares are held by independent realms (separate servers)
- No single realm has enough information to reconstruct the keys alone
- Recovery requires your PIN and cooperation from enough realms
- Wrong PINs are rate-limited to slow guessing
You do not configure Juicebox servers by hand for the normal path. The Chat XDK includes the Juicebox client; realm configuration comes from the X API as
juicebox_config on your public-key record. First-time PIN storage and later unlock are Chat XDK calls—see Getting Started and register public keys. Some apps (especially servers and bots) use an exported key blob instead of Juicebox; protect that material like a password.Signatures explained
Every X Chat message includes a digital signature that supports:- Authenticity — it was produced with the sender’s signing private key
- Integrity — the encrypted content was not modified after signing
How signatures work (conceptually)
If anything in the signed material changes, verification fails. Only someone with the signing private key can produce a valid signature for that key.
In your app
The Chat XDK signs when you encrypt outbound messages and verifies when you decrypt inbound ones against the sender’s public key material (from the public-key APIs). Verification is mandatory by default: the SDK rejects unverified signed events unless you explicitly disable the check (not recommended). Details are in the Chat XDK reference.Signed state changes (action signatures)
Messages are not the only signed material. Every call that changes conversation state—adding or rotating conversation keys, creating a group, adding members—must carry one or more action signatures: the sender signs a payload describing exactly what the change does (for a key change, that payload includes the new conversation key itself), and the API rejects the request if the signatures are missing or malformed. Because the server never holds the plaintext conversation key, it cannot check a key change’s signature cryptographically; it validates that the signed, encoded description of the change matches the request it received. The cryptographic check happens at the edges: each recipient’s Chat XDK verifies the signature against the sender’s signing public key when it decrypts the key-change event. The Chat XDK’sprepare methods produce these signatures for you—group creates and member adds return two (the key change plus the group action), and both must be sent.
Signatures are bound to the event contents and are immutable: an event whose signature does not verify can never become valid later. See Troubleshooting for how to treat those.
Security properties
What X Chat protects against
What X Chat does not protect against
Glossary
Next steps
Getting Started
Implement keys, send, and receive step by step
Chat XDK Reference
Encryption SDK methods and types
Introduction
Product overview and architecture
Real-time events
How encrypted events are delivered