--- title: "Rocket.Chat End-to-End Encryption Specs" slug: "end-to-end-encryption-specifications" description: "Understand Rocket.Chat end-to-end encryption specifications for secure data transmission, privacy compliance, and robust SaaS protection." updated: 2026-10-20T14:44:51Z published: 2026-10-20T14:44:51Z canonical: "docs.rocket.chat/end-to-end-encryption-specifications" stale: true --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.rocket.chat/llms.txt > Use this file to discover all available pages before exploring further. # End-to-End Encryption Specifications [End-to-End Encryption (E2EE)](https://en.wikipedia.org/wiki/End-to-end_encryption) is a secure communication method that ensures only message senders and recipients can read the content of messages and files. Rocket.Chat enhances security by supporting E2EE for private and direct conversations. This document explains the technical implementation of E2E Encryption in Rocket.Chat, including key generation, encryption processes, and how the system manages encrypted data. It is intended to supplement the [user guide](https://docs.rocket.chat/docs/end-to-end-encryption-user-guide) with a deeper technical context. ## Key concepts and components > [!WARNING] > IMPORTANT: Consider the limitations of E2E Encryption before enabling it: > > - **Encrypted messages will not appear in search results** > - **Encrypted content cannot be audited** > - **Bots may not be able to access encrypted messages unless explicitly supported** > > Found a bug? Please [report it to Rocket.Chat](https://developer.rocket.chat/docs/contribute-through-bug-reporting). ### Encryption password and master key When a user logs in for the first time, the client automatically generates a **mnemonic recovery phrase** and prompts the user to save it securely. This phrase is used to derive a **256-bit AES-GCM Master Key** through a secure key-derivation process. The Master Key encrypts and decrypts the user’s private key, which is essential for securing end-to-end encrypted messages. ### Public-private key pair (Ku, Kr) Each user has a public-private key pair **(Ku, Kr)** generated by the client upon first login. The public key **(Ku)** is stored on the server, while the private key **(Kr)** is first encrypted using the AES-GCM Master Key derived from the user’s mnemonic recovery phrase and then sent to the server for secure storage in the user record. If a public-private key pair already exists in the database for the user, it is downloaded from the server instead of being generated again. The downloaded public key is used as-is, and the encrypted private key is decrypted locally using the **Master Key**. If the master key has not yet been unlocked on the client, the user is prompted to enter their **recovery phrase** to restore access. ### Session key (Ks) The public key encrypts a persistent session key (**Ks**), which is then used to encrypt messages and files. This encrypted session key is stored in the database in the Subscription model for every user in a room (including the user who initiates the **E2EE** session). > [!WARNING] > **This method works for direct messages and groups since direct messaging is just a room with only two people in it.** ### Message encryption and decryption When starting a new **E2EE** session, if an existing session key exists in the current user's room subscription, it is downloaded and decrypted using the user’s private key and then used to encrypt future messages. If an existing session key is not found in the database, the current user generates a new one, which is then encrypted for every user in the room and stored in the database. Once a session key has been obtained above, we enter **E2EE** mode, and all messages sent henceforth are encrypted using this session key. Because keys are stored in the database and are persistent, the other users in the room do not need to be online to participate in an **E2EE** conversation. ## Code references The relevant code for Rocket.Chat’s E2EE implementation is located in the following location: - [E2EE client code](https://github.com/RocketChat/Rocket.Chat/tree/develop/apps/meteor/client/lib/e2ee) - [Helper function](https://github.com/RocketChat/Rocket.Chat/blob/develop/apps/meteor/client/lib/e2ee/helper.ts) ## Algorithms and encryption standards - **Client key pair:** RSA-OAEP, 2048-bit (SHA-256) - **Master key:** AES-GCM, 256-bit, PBKDF2 with 100,000 iterations and random salt - **Session key:** AES-GCM, 256-bit ## Encryption process ### 1. User login and key generation When users log in, they are prompted for their E2EE password. This password is used to generate the **Master Key** through a **Password-Based Key Derivation Function (PBKDF2)**. The server then checks whether a public-private key pair already exists for the user: - If an existing key pair is found, the **private key** is downloaded and decrypted using the **Master Key**. - If no key pair exists, a new one is generated. ### 2. Client startup During startup, the function `startClient()` in `rocketchat.e2e.ts` verifies whether the client’s local storage contains a public-private key pair. - If no key pair is found, the client is treated as new, and a new **RSA-OAEP** key pair is generated using the following call: ```typescript crypto.subtle.generateKey({    name: 'RSA-OAEP',    modulusLength: 2048,    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),    hash: {        name: 'SHA-256'    } }, true, ['encrypt', 'decrypt']); ``` The generated key pair is stored in the client’s local storage in serialized (JSON-stringified) form. The public key and encrypted private key are also uploaded to the server database through the `e2e.setUserPublicAndPrivateKeys` API method. ### 3. Starting an E2EE session When a client joins a room, the `handshake()` function in `rocketchat.e2e.room.js` initiates the session setup. The process begins by checking the database for an encrypted **session key** associated with the user-room pair: - If an encrypted session key exists, it is decrypted using the client’s private key, and the E2EE session begins. - If no session key exists, a new **AES-GCM session key** is generated using: ```typescript crypto.generateKey({name: 'AES-GCM', length: 256}, true, ['encrypt', 'decrypt']) ``` Once created, the session key must be distributed securely to all users in the room: 1. **Fetch public keys** for all users in the room using the `getUsersOfRoomWithoutKeys()` server method, which returns each user’s ID and public key. This is done in batches, meaning some users may receive their keys earlier than others. 2. **Encrypt** the new session key with each user’s public key. 3. **Share** the encrypted key by calling `provideUsersSuggestedGroupKeys()`. This adds the encrypted session key as a `suggestedKey` to each user’s subscription. This process works asynchronously, users do not need to be online at the same time. As long as one user with the session key remains online, key distribution continues until all users with valid public keys have received their suggested keys. When users log in, they receive the suggested keys through their subscriptions. Each client evaluates the keys and either **accepts** or **rejects** them: - If **accepted**, the suggested key is moved to the `E2EKey` property in the user’s subscription, enabling encrypted communication. - If **rejected**, the suggested key is removed, and the user is added to a virtual queue awaiting key distribution from other users. After these steps, the E2EE session is successfully established using the new session key. ### 4. Sending encrypted messages When a user sends a message, the `onClientBeforeSendMessage` event is triggered. If E2EE is active: - The message content is encrypted using the **session key**. - The encrypted message is placed inside an object with the following structure: ```typescript final_message: {  msg: ,  t: "e2e" } ``` Here: - `msg`: contains the encrypted message. - `t`: identifies the message type (`"e2e"`) to distinguish it from unencrypted messages. This object is then sent to the recipient, ensuring only the intended recipient can decrypt and view the message. The original plaintext message remains inaccessible to others. ### 5. Receiving encrypted messages When a message is received, the `onClientMessageReceived` event intercepts it. - If the message type (`t`) is not `"e2e"`, the message is plain text and requires no decryption. - If the message type is `"e2e"`, the client decrypts the `msg` field using the **session key**. If the receiving client does not already have the session key in its local storage, it retrieves the encrypted key from the server using the `fetchGroupE2EKey` method. The client then decrypts it with its private key and uses the resulting session key to decrypt incoming messages. ## APIs Rocket.Chat provides several server methods that support E2EE operations, including key generation, distribution, and session management. > [!WARNING] > This section summarizes the available E2EE-related APIs for context. For the complete and most accurate specifications, including request/response payloads, parameter descriptions, and examples, refer to the official [E2E API documentation.](https://developer.rocket.chat/apidocs/e2ee-api) The following methods are available for managing E2EE keys and related operations. ### 1. `e2e.setUserPublicAndPrivateKeys` Saves the user’s public key and encrypted private key to the server. **Request:** ```json key = {  RSA-PubKey: ,  RSA-EPrivKey: } ``` **Response:** ```json { success: true } ``` ### 2. `fetchMyKeys()` Retrieves the current user’s public key and encrypted private key from the server database. **Request:** ```json {} ``` **Response:** ```json key = {  RSA-PubKey: ,  RSA-EPrivKey: } ``` ### 3. `e2e.getUsersOfRoomWithoutKey` Returns the list of users in a selected room who are waiting for E2E keys, including their public keys and user IDs. **Request:** ```json rid = the room's ID ``` **Response:** ```json {  success: true,  users: [    { userId: 'xxx', public_key: 'xxxx' }  ] } ``` ### 4. `e2e.setRoomKeyId` Defines the **keyID** for a room. The keyID is derived from the encryption key and is used to identify the correct encryption key in rooms with multiple room keys. **Request:** ```json rid = keyID = ``` **Response:** ```json { success: true } ``` ### 5. `e2e.updateGroupKey` Updates a user’s **Group (Session) Key**. When a user creates a new conversation and generates Session Keys, they define this Session Key in their own subscription. After that, they can share the key with other users. If the `uid` parameter differs from the user making the call, the encrypted key is defined as that user’s **Suggested Key**. **Request:** ```json uid = rid = key = ``` **Response:** ```json { success: true } ``` ### 6. `e2e.acceptSuggestedGroupKey` Marks a validated **Suggested Key** as valid and sets it as the user’s active Session Key. If there are any `oldKeys` associated with the user, they are also accepted. **Request:** ```json {} ``` **Response:** ```json { success: true } ``` ### 7. `e2e.rejectSuggestedGroupKey` Rejects a **Suggested Key** after validation. The key is removed from the user’s subscription, and the user is placed back into the waiting queue for key distribution. **Request:** ```json {} ``` **Response:** ```json { success: true } ``` ### 8. `e2e.provideUsersWithSuggestedGroupKeys` Provides users in a room who are waiting for keys with a **Suggested Key**. The suggested key is stored in the `E2ESuggestedKey` property of each user’s subscription, allowing them to validate it the next time they come online. **Request:** ```json usersSuggestedGroupKeys = {  userId: ,  key: ,  oldKeys: [] } ``` **Response:** ```json { success: true } ``` ### 9. `e2e.resetRoomKey` Allows an authorized user to reset the **Session Key** for all users in a room. **Request:** ```json rid = e2eKey = e2eKeyId = ``` **Response:** ```json { success: true } ``` ## Push notifications of E2EE messages ### Overview Push notifications for messages in E2EE rooms contain only the encrypted payload of the message. Decryption of this payload occurs locally on mobile clients (iOS and Android) before the message is displayed. ### Process The server is responsible for sending push notifications. However, it **does not store unencrypted message content** from E2EE rooms, only the encrypted message string. These encrypted strings can be decrypted **only** with the user’s private key, which remains securely stored on their device. When a new push notification for an E2EE message arrives, it includes the following parameter: ```plaintext messageType: 'e2e' ``` Upon receiving such a notification: 1. The mobile client identifies the message as encrypted. 2. It attempts to decrypt the payload using: - The **user’s locally stored private key**, and - The **E2EE key** associated with the room from which the message originated. 3. If both keys are available, the client decrypts the message locally and displays the plaintext content. Throughout this process, **only the encrypted message content** is transmitted via push notification gateways, never plaintext data. > [!WARNING] > This feature is available in the **Community Edition**. ### Fetching full message content from the server on receipt ![](https://cdn.us.document360.io/6ae79a05-7252-45d0-96e8-8f375e07b1b2/Images/Documentation/Premium(5).svg) For enhanced security, [premium plans](/v1/docs/our-plans) introduce an additional push notification mode: `Fetch full message content from the server on receipt` In this mode: - The push gateways (e.g., Google, Apple, or others) do not transmit any message content, encrypted or otherwise. - Instead, only a notification trigger is sent, indicating that a new message should be fetched. - Once the Rocket.Chat client receives this trigger, it retrieves the message content directly from the server and displays it as a push notification. This approach ensures that no message data, even in encrypted form, passes through external push notification services. ## Multiple room keys + reset room keys ### Overview Due to the nature of End-to-End Encryption (E2EE), if all users lose their Session Keys for a conversation, the previously encrypted messages become unrecoverable unless the encryption is somehow broken, which is typically not feasible. The same principle applies in Rocket.Chat. If all participants in a conversation lose access to their Session Keys, that conversation is permanently inaccessible. However, even though past messages cannot be decrypted, it may still be necessary to continue communication in the same room without creating a new one or disabling E2EE. To address this scenario, Rocket.Chat supports resetting encryption keys for a conversation. When a user resets the Session Keys for a room, all participants’ previous keys are removed from their subscriptions, allowing them to receive a new key and continue the conversation seamlessly. The process proceeds as follows: ![](https://cdn.us.document360.io/6ae79a05-7252-45d0-96e8-8f375e07b1b2/Images/Documentation/image-20240921-130001.png) E2EE room key reset flow ### Reset process 1. **User A** resets the Session Key in room **Z**. 2. **User A** creates a new Session Key and derives a new **KeyID**. 3. The server removes the **E2EKey** property from all users in the room. 4. A new room key is distributed to the other users, allowing the conversation to continue securely. > [!WARNING] > The terms *Session Key* and *Room Key* are used interchangeably in this document. ### Handling existing keys If some users still have an **E2EKey** on their subscription, the server cannot determine whether it remains valid. To prevent potential data loss, Rocket.Chat moves the user’s `E2EKey` to a new property called **oldRoomKeys**. This array contains the keys that existed on the user’s subscription at the time of a room key reset. Clients use this information to attempt decryption of old messages. ### Decryption process 1. Each message consists of: ```plaintext keyID + encrypted content ``` 2. The client attempts to match the `keyID` prepended to the message with the `keyID` stored in the room object (current Session Key). 3. If the `keyID`s match, the client uses the **current Session Key** to decrypt the message. - If decryption fails, the UI displays the message: `Messaage cannot be decrypted due to a key error.` 4. If the `keyID`s do **not** match, the client searches for a key with the given `keyID` in the `oldRoomKeys` list: a. If a matching key is found, the message is decrypted using that key. b. If no match is found, the client attempts to decrypt using the latest key. c. If all attempts fail, the message is considered **indecipherable**. > [!WARNING] > The same decryption logic applies to **file encryption**. ### Managing old room keys If a user has old room keys, the key suggestion process accommodates them by allowing the reuse of old keys in the same way as current encryption keys. The `oldRoomKeys` array is limited to **10 elements**. When this limit is exceeded, the oldest key is deleted, which may render some older messages indecipherable. When this occurs, the client displays the following message: `This message cannot be decrypted due to multiple room key resets.` ## FAQs **If there are still users with an `E2EKey` for the room, why not wait for them to come online and share the key?** Waiting for those users is not always practical or reliable, especially if they’ve lost access to their device, uninstalled the app, or never reconnect. Resetting the room key ensures the conversation can continue securely for all active participants. **If I need to lose my keys to see the *Reset Room Key* button, does that mean I’ll never have old room keys?** Not necessarily. The *Reset Room Key* button appears when the client no longer has access to the valid Session Key. However, when a reset occurs, previous keys are moved into `oldRoomKeys`, allowing you to decrypt older messages (until the retention limit is reached). **What happens to older encrypted messages after a room key reset?** After a reset, old messages remain stored on the server in their encrypted form. However, they can only be decrypted using the corresponding old room keys (if still available in `oldRoomKeys`). Once those keys are purged (after 10 resets), the older messages become permanently indecipherable. **Who can perform a room key reset?** Only users with the appropriate authorization level (for example, room owners or administrators) can initiate a room key reset. Regular users cannot trigger this operation. **Does resetting a room key affect users who are offline?** Yes. When those users come back online, their old `E2EKey` is automatically moved to `oldRoomKeys`, and they’ll receive the new session key via the standard key distribution process. **Can bots or integrations access messages after a key reset?** Not unless explicitly configured for E2EE support. Since bots do not automatically receive new keys, they lose access to both old and new encrypted messages unless reauthorized. **How many times can I reset room keys before messages are lost?** You can reset up to 10 times before the oldest `oldRoomKeys` entry is removed. Once the 11th reset occurs, any messages encrypted with the removed key become permanently unreadable. **Can I export or back up my E2EE keys?** Rocket.Chat does not export encryption keys directly for security reasons. Users should securely store their mnemonic recovery phrase, which allows re-deriving the master key when needed.