Unverified Commit d1438015 authored by Faria Masood's avatar Faria Masood Committed by gitbook-bot
Browse files

GitBook: [master] 2 pages modified

parent caed08fe
......@@ -202,6 +202,7 @@
* [Tags](guides/omnichannel-guides/omnichannel-manger-guides/tags.md)
* [Priorities](guides/omnichannel-guides/omnichannel-manger-guides/priority-queue.md)
* [Security and Compliance Guides](guides/security/README.md)
* [End-to-End Encryption Algorithms](guides/security/end-to-end-encryption-algorithms.md)
* [Security fixes and updates](guides/security/security-updates.md)
* [Compliance Resources](guides/security/compliance-resources.md)
* [Developer Guides](guides/developer/README.md)
description: >-
The following contains an overview of the implemented mechanisms of the
Rocket.Chat End to End Encryption feature. It provides technical information
and supplements the user guide.
# End-to-End Encryption Algorithms
## Encryption Process Overview ****
First of all, upon login, the client auto-generates the encryption password and asks the user to save it. This password is used to generate a secure 256-bit **AES-CBC** encryption key, called “**Master** **Key**”.
For using end to end encryption \(**E2EE**\), the client \(**C**\) of a user \(**U**\) needs to have a Public-Private key pair \(**Ku, Kr**\). This key pair is generated when the user logs in with a client for the first time. The public key is sent to the server and stored in the database in the User model. The private key is first encrypted using the Master key and then sent to the server for storing in the User model database. If a public-private key pair already exists in the database for the user, instead of generating it again, it is downloaded from the server. The downloaded public key is used as-is, and the encrypted private key is first decrypted using the master key. If the master key has not been decrypted client-side already, the user is prompted to enter the master key again.
The public key is used to encrypt a persistent session key \(**Ks**\), which is then used for the actual encryption of 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\). Note that this method works for direct messages as well as groups since direct messaging is just a room with only two people in it.
When starting a new **E2EE** session, first, if an existing session key exists in the room subscription of the current user, it is downloaded and decrypted using the user’s private key and then used to encrypt future messages. In case an existing session key is not found in the database, a new session key is generated by the current user and then stored in the database encrypted for every user in the room.
Once a session key has been obtained in the above manner, 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
Relevant code for E2EE is located in
\(rocket.chat/app/e2e/client\) [_https://github.com/RocketChat/Rocket.Chat/tree/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client_](https://github.com/RocketChat/Rocket.Chat/tree/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client)\_\_
_\(rocket.chat/app/e2e/client\)_ [https://github.com/RocketChat/Rocket.Chat/tree/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client](https://github.com/RocketChat/Rocket.Chat/tree/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client)
[https://github.com/RocketChat/Rocket.Chat/blob/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client/helper.js ](https://github.com/RocketChat/Rocket.Chat/blob/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client/helper.js)[https://github.com/RocketChat/Rocket.Chat/blob/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client/helper.js](https://github.com/RocketChat/Rocket.Chat/blob/2bf8edab056dbc5e0d40aeae2c4472f729ec09d9/app/e2e/client/helper.js)
contains the technical specifications of the implementation of E2EE.
## Algorithms Used
Specifically, **E2EE** uses:
`- client key pair: RSA-OAEP, length 2048`
`- master key: AES-CBC, length 256, iterations: 1000`
`- session key: AES-CBC, length 128`
## Architectural Specifications
1. **User Login:** As soon as the user logs in, we ask for their “**E2E** **password**”. Using this password with a **PBKDF** \(Password-based Key Derivation Function\), we generate a “Master Key”. We then check the server database for whether a public-private key pair exists for this user. If it does, we download that key pair. The public key is used as-is. The private key is in encrypted form and will be decrypted using the master key before it can be used.
2. **Client Startup:** Using _`startClient()`_ in `rocketchat.e2e.js`, check the local storage of the client to determine whether this is a new client or not. If local storage does not have the public-private key pair for this client, then this is treated as a new client and this RSA-OAEP key pair is generated using a function call to: `crypto.subtle.generateKey({name: 'RSA-OAEP', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: 'SHA-256'}}, true, ['encrypt', 'decrypt']);` This key pair is finally stored in the client’s local storage in a serialized form \(JSON-stringified\). This serial form of the public key and encrypted private key is also sent over to the server database using a server-method call to `addKeyToChain()`.
3. The client starts the encryption session from the E2E flex tab button: The handshake\(\) function in rocketchat.e2e.room.js is called for the room where the client started the session. First, try fetching an encrypted session key from the subscription for this user-room pair, from the database. If this key is found, decrypt this using the client’s private key and the **E2EE** session is started using this decrypted key. If the user’s subscription to this room does not contain a key, generate a new AES-CBC session key for use. This is done by a function call to: `RocketChat.E2E.crypto.generateKey({name: 'AES-CBC', length: 128}, true, ['encrypt', 'decrypt'])` Once a key has been generated, it has to be stored, encrypted, in the subscriptions of all users in the current room. This is done by: Fetch public keys for all users in the room using server-method calls to `getUsersOfRoom()` and `fetchKeychain()`. One by one, encrypt the newly generated session key using each of these public keys, and store this encrypted key in the corresponding user’s subscription to this room using a server-method call to `updateGroupE2EKey()`. **E2EE** session is now started using the generated session key. 4. Client sends a message: Making use of the `onClientBeforeSendMessage` event when the user sends the message, the message object is encrypted using the session key obtained in the previous step when **E2E** is in session. This encrypted message is wrapped in another object, in a “msg” parameter and a new parameter for type, called “t”, is added to this new object with value “**e2e**” to distinguish it from a regular message. Thus, the new object becomes:
`final_message: {`
`msg: <encrypted_message>,`
`T: “e2e” }` ****
This new object is sent to the other client. Note that the original message is not visible to anyone, and only the encrypted message is sent.
5. Client receives a message: When a message object is received, using the \``onClientMessageReceived` event, we intercept it and check whether the “t” type parameter of the message object is “**e2e**”, like we set when sending the message. If it is not, we don't need to decrypt it as it is a plaintext message and **E2EE** was not used. If it is an encrypted message, we take the “msg” parameter’s value and decrypt that message using the session key.
Note that if the receiving client does not have the session key in its local storage, it will have to download the encrypted session key from the server using the `fetchGroupE2EKey`\`method, and then decrypt it using its own private key, and then use this key for decryption of the incoming message.
## Server Methods ****
### 1. `addKeyToChain(key)`
For saving a newly generated public key to the database for the current user.
`key = {`
`RSA-PubKey: “< The generated public key for a client>”,`
`RSA-EPrivKey: “<` **``**`Generated private key, encrypted using the master key>”`
The keys have been converted from ArrayBuffer to String format before sending them.
**Response:** null
### 2. fetchGroupE2EKey\(rid\)
For fetching the encrypted session key for a conversation, for the current user.
`rid = The room id of a conversation` \(either of direct or private\).
The **E2EE** session key for the current user, for that conversation.
### 3. fetchKeychain\(userId\)
For fetching the public key of a user \(to be used for encrypting the session key for that user\)
`userId = The id of a user.`
`RSA-PubKey: “< The public key for that user>”,`
`RSA-EPrivKey: “< The private key, encrypted using the master key>”`
### 4. updateGroupE2EKey\(rid, uid, key\)
For saving an encrypted session key to the database, for a user.
`rid = The room id of a conversation (either of direct or private).`
`uid = The id of a user.`
`key = The E2EE Session key for that user, for that conversation.`
`{ RocketChat subscription object }`
### 5. emptyKeychain\(\)
Clears out the current user’s public and encrypted private keys from the server database.
**Request:** {}
**Response:** {}
### 6. fetchMyKeys\(\)
Fetches current user’s public and encrypted private keys from the server database.
**Request:** {}
`RSA-PubKey: “<The public key for current user>”,`
`RSA-EPrivKey: “<The private key, encrypted using the master key>”`
`}` **``**
## REST API routes for encryption-related requests
Each route directly corresponds to one server DDP method described above. These routes follow the same naming system as the DDP methods described above. Please refer to the above description to know more about the individual request/response pairs for each route.
`GET e2e.fetchGroupE2EKey(rid)`
`GET e2e.fetchKeychain(uid)`
`GET e2e.fetchMyKeys()`
`POST e2e.addKeyToChain(RSAPubKey, RSAEPrivKey)`
`POST e2e.emptyKeychain()`
`POST e2e.updateGroupE2EKey(uid, rid, key)`
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment