Group Encryption (Sender Keys)
Relevant source files
The following files were used as context for generating this wiki page:
Group Encryption in Baileys utilizes the "Sender Keys" protocol to provide efficient End-to-End Encryption (E2EE) for group communications. Unlike one-to-one messaging where each message is encrypted individually for every recipient, Sender Keys allow a sender to generate a single encrypted payload that can be decrypted by all authorized group members. This significantly reduces the computational and bandwidth overhead required for large groups while maintaining cryptographic security.
The implementation relies on distributing a SenderKeyDistributionMessage to group participants, which establishes the necessary session state for subsequent group messages (known as skmsg). The system handles the rotation of keys, tracking of message iterations, and synchronization between identities (PN vs LID).
Sources: lib/Socket/messages-send.js:371-404, lib/Signal/libsignal.js:101-118
Core Architecture and Components
The group encryption system is composed of several specialized classes and data structures that manage the lifecycle of a sender's group session.
Key Classes and Structures
| Component | Description |
|---|---|
GroupCipher | Handles the high-level encryption of plaintexts into group messages and the decryption of incoming group messages. |
GroupSessionBuilder | Responsible for creating and processing distribution messages to establish shared group state. |
SenderKeyRecord | A persistent container that stores the state of a sender's key for a specific group. |
SenderKeyState | Represents the current state of a session, including the chain key, signing keys, and message keys. |
SenderKeyName | A unique identifier for a sender's key in a specific group, combining the group JID and the sender's address. |
Sources: lib/Signal/Group/index.js:38-48, lib/Signal/Group/group_cipher.js:8-12
Object Relationship
The following diagram illustrates how the core components interact to manage group cryptographic state.
Encryption Process
When a message is sent to a group, the system first ensures that all recipients have the sender's current distribution key. The message itself is then encrypted once using a SenderMessageKey derived from the sender's chain.
Message Distribution Flow
- Deduplication: The system deduplicates participant JIDs, preferring LID (Linked ID) over PN (Phone Number) when both exist to maintain a single encryption layer.
- Session Assertion: The system checks for existing sessions with all participants. Missing sessions trigger a fetch from the server.
- Key Distribution: If participants haven't received the current sender key, a
SenderKeyDistributionMessageis bundled and sent viapkmsgormsg. - Group Encryption: The message content is encrypted into an
skmsg(Sender Key Message).
The GroupCipher.encrypt Method
The GroupCipher handles the iteration of the chain key and the production of the final SenderKeyMessage.
- It loads the
SenderKeyRecordfor theSenderKeyName. - It retrieves the current
SenderChainKeyand increments the iteration. - It derives a
SenderMessageKey(consisting of an IV and Cipher Key). - It performs AES encryption on the padded plaintext.
Sources: lib/Signal/Group/group_cipher.js:13-31
Decryption and Message Processing
Incoming group messages (marked with type="skmsg") are routed to the decryptGroupMessage method in the Signal repository.
Decryption Logic
- Record Retrieval: The
SenderKeyRecordis loaded using the author's JID and the group JID. - Signature Verification: The
SenderKeyMessagesignature is verified against the author's public signing key stored in theSenderKeyState. - Key Derivation: The system looks for a message key matching the message's iteration. If the message is from the future, the chain key is advanced, and intermediate keys are cached.
- AES Decryption: The ciphertext is decrypted using the derived IV and Cipher Key.
Handling Future and Old Messages
The protocol includes safeguards against message loss and out-of-order delivery:
- Cached Keys: If a message arrives with a higher iteration than the current local state, the
GroupCipheradvances the chain and stores the intermediateSenderMessageKeys in theSenderKeyState. - Future Limit: The system will not advance more than 2000 messages into the future to prevent resource exhaustion attacks.
- Old Counters: Messages with iterations lower than the current chain are only decryptable if their specific message key was previously cached.
Sources: lib/Signal/Group/group_cipher.js:52-78
Protocol Messages
The underlying protocol uses specific Protobuf structures for group key management.
| Message Type | Fields | Description |
|---|---|---|
SenderKeyDistributionMessage | id, iteration, chainKey, signingKey | Used to share the initial root of a sender's chain with a group member. |
SenderKeyMessage | id, iteration, ciphertext | The standard encrypted message format for group communication. |
Sources: WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.js:283-301, WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.js:521-536
LID and PN Synchronization
Baileys implements a single encryption layer strategy where LID (Identity) is preferred over PN (Phone Number). When the system detects an LID mapping for a PN participant, it performs a session migration. This involves copying the SessionRecord to the LID address and deleting the old PN session, ensuring that group encryption remains consistent across device identity changes.
Sources: lib/Socket/messages-send.js:256-304, lib/Signal/libsignal.js:160-221
Conclusion
Group Encryption via Sender Keys provides a scalable solution for secure group chat by shifting from $O(N)$ encryption operations per message to $O(1)$ encryption with $O(N)$ key distribution. Through the use of GroupCipher and SenderKeyRecord, Baileys ensures that group messages remain confidential, authenticated, and resilient to out-of-order delivery.