From 6955cd3e9310279d3ceb63f2c9991bdd347796fe Mon Sep 17 00:00:00 2001 From: Alex Kaminskii Date: Wed, 12 Oct 2022 14:19:25 +0200 Subject: [PATCH] feat(frontend): mob file decryption --- .../MessageDistributor/MessageDistributor.ts | 14 ++++++---- .../MessageDistributor/network/crypto.ts | 28 +++++++++++++++++++ frontend/app/types/session/session.ts | 1 + 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 frontend/app/player/MessageDistributor/network/crypto.ts diff --git a/frontend/app/player/MessageDistributor/MessageDistributor.ts b/frontend/app/player/MessageDistributor/MessageDistributor.ts index 7af44e879..69a195663 100644 --- a/frontend/app/player/MessageDistributor/MessageDistributor.ts +++ b/frontend/app/player/MessageDistributor/MessageDistributor.ts @@ -28,6 +28,7 @@ import AssistManager from './managers/AssistManager'; import MFileReader from './messages/MFileReader'; import { loadFiles, requestEFSDom, requestEFSDevtools } from './network/loadFiles'; +import { decryptSessionBytes } from './network/crypto'; import { INITIAL_STATE as SUPER_INITIAL_STATE, State as SuperState } from './StatedScreen/StatedScreen'; import { INITIAL_STATE as ASSIST_INITIAL_STATE, State as AssistState } from './managers/AssistManager'; @@ -215,14 +216,17 @@ export default class MessageDistributor extends StatedScreen { } private loadMessages() { - const createNewParser = () => { + const createNewParser = (shouldDecrypt=true) => { + const decrypt = shouldDecrypt && this.session.fileKey + ? (b: Uint8Array) => decryptSessionBytes(b, this.session.fileKey) + : (b: Uint8Array) => Promise.resolve(b) // Each time called - new fileReader created const fileReader = new MFileReader(new Uint8Array(), this.sessionStart) - return (b: Uint8Array) => { + return (b: Uint8Array) => decrypt(b).then(b => { fileReader.append(b) this.parseAndDistributeMessages(fileReader) this.setMessagesLoading(false) - } + }) } this.setMessagesLoading(true) this.waitingForFiles = true @@ -230,7 +234,7 @@ export default class MessageDistributor extends StatedScreen { loadFiles(this.session.domURL, createNewParser()) .catch(() => // do if only the first file missing (404) (?) requestEFSDom(this.session.sessionId) - .then(createNewParser()) + .then(createNewParser(false)) // Fallback to back Compatability with mobsUrl .catch(e => loadFiles(this.session.mobsUrl, createNewParser()) @@ -245,7 +249,7 @@ export default class MessageDistributor extends StatedScreen { loadFiles(this.session.devtoolsURL, createNewParser()) .catch(() => requestEFSDevtools(this.session.sessionId) - .then(createNewParser()) + .then(createNewParser(false)) ) //.catch() // not able to download the devtools file .finally(() => update({ devtoolsLoading: false })) diff --git a/frontend/app/player/MessageDistributor/network/crypto.ts b/frontend/app/player/MessageDistributor/network/crypto.ts new file mode 100644 index 000000000..754d449f7 --- /dev/null +++ b/frontend/app/player/MessageDistributor/network/crypto.ts @@ -0,0 +1,28 @@ + + +const u8aFromHex = (hexString:string) => + Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))) + +const is16BitHex = (maybeHex: string | undefined) => + maybeHex && maybeHex.length % 2 === 0 && !/[^a-fA-F0-9]/u.test(maybeHex) + + +function truncPadding(padded: Uint8Array): Uint8Array { + let i = padded.length - 1 + for (; !padded[i] ;i--) {} + return padded.subarray(0, i) +} + +export function decryptSessionBytes(cypher: Uint8Array, keyString: string): Promise { + const [hexKey, hexIV] = keyString.split(",") + if (!is16BitHex(hexIV) || !is16BitHex(hexKey)) { + return Promise.reject("Wrong key/iv pair") + } + const iv = u8aFromHex(hexIV) + const byteKey = u8aFromHex(hexKey) + return crypto.subtle.importKey("raw",byteKey, { name: "AES-CBC" }, false, ["decrypt"]) + .then(key => crypto.subtle.decrypt({ name: "AES-CBC", iv: iv}, key, cypher)) + .then(truncPadding) +} + + diff --git a/frontend/app/types/session/session.ts b/frontend/app/types/session/session.ts index e8aa8b80c..77e8b02f6 100644 --- a/frontend/app/types/session/session.ts +++ b/frontend/app/types/session/session.ts @@ -83,6 +83,7 @@ export default Record({ agentToken: '', notes: [], notesWithEvents: [], + fileKey: '', }, { fromJS:({ startTs=0,