Skip to content

Commit

Permalink
decrypt oldkeys when received instead of every message
Browse files Browse the repository at this point in the history
  • Loading branch information
KevLehman committed Sep 27, 2024
1 parent 1f72704 commit 60bc3ab
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 10 deletions.
40 changes: 30 additions & 10 deletions apps/meteor/app/e2e/client/rocketchat.e2e.room.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class E2ERoom extends Emitter {

this.once(E2ERoomState.READY, () => this.decryptPendingMessages());
this.once(E2ERoomState.READY, () => this.decryptSubscription());
this.once(E2ERoomState.READY, () => this.decryptOldRoomKeys());
this.on('STATE_CHANGED', (prev) => {
if (this.roomId === RoomManager.opened) {
this.log(`[PREV: ${prev}]`, 'State CHANGED');
Expand Down Expand Up @@ -210,6 +211,27 @@ export class E2ERoom extends Emitter {
this.log('decryptSubscriptions Done');
}

async decryptOldRoomKeys() {
const sub = Subscriptions.findOne({ rid: this.roomId });

if (!sub?.oldRoomKeys || sub?.oldRoomKeys.length === 0) {
this.log('decryptOldRoomKeys nothing to do');
return;
}

const decryptedOldKeys = await Promise.all(
sub.oldRoomKeys.map(async (key) => {
return {
...key,
E2EKey: await this.decryptSessionKey(key.E2EKey),
};
}),
);

this.oldKeys = decryptedOldKeys;
this.log('decryptOldRoomKeys Done');
}

async decryptPendingMessages() {
return Messages.find({ rid: this.roomId, t: 'e2e', e2e: 'pending' }).forEach(async ({ _id, ...msg }) => {
Messages.update({ _id }, await this.decryptMessage(msg));
Expand Down Expand Up @@ -265,6 +287,7 @@ export class E2ERoom extends Emitter {
}

async decryptSessionKey(key) {
console.log('Decrypting key: ', key);
key = key.slice(12);
key = Base64.decode(key);

Expand Down Expand Up @@ -518,29 +541,26 @@ export class E2ERoom extends Emitter {

let oldKey = '';
if (keyID !== this.keyID) {
const sub = Subscriptions.findOne({ rid: this.roomId });
const { oldRoomKeys = [] } = sub;
const oldRoomKey = oldRoomKeys.find((key) => key.e2eKeyId === keyID);
const oldRoomKey = this.oldKeys?.find((key) => key.e2eKeyId === keyID);
// Messages already contain a keyID stored with them
// That means that if we cannot find a keyID for the key the message has preppended to
// The message is indecipherable. In such cases, we'll try to decrypt with the most recent key
if (oldRoomKey) {
oldKey = oldRoomKey.E2EKey;
} else if (oldRoomKeys.length) {
oldKey = oldRoomKeys[oldRoomKeys.length - 1]?.E2EKey;
}
}

if (oldKey) {
oldKey = await this.decryptSessionKey(oldKey);
}

message = message.slice(12);

const [vector, cipherText] = splitVectorAndEcryptedData(Base64.decode(message));

try {
// For indecipherable messages, we're going to try to decrypt with the most recent key
const result = await decryptAES(vector, oldKey || this.groupSessionKey, cipherText);
return EJSON.parse(new TextDecoder('UTF-8').decode(new Uint8Array(result)));
} catch (error) {
return this.error('Error decrypting message: ', error, message);
this.error('Error decrypting message: ', error, message);
return { msg: `Message cannot be decrypted with current keys. KeyID ${keyID}` };
}
}

Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/e2e/client/rocketchat.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class E2E extends Emitter {
}

await e2eRoom.decryptSubscription();
await e2eRoom.decryptOldRoomKeys();
}, 0);
},
added: (sub: ISubscription) => {
Expand Down

0 comments on commit 60bc3ab

Please sign in to comment.