54 lines
1.5 KiB
JavaScript
54 lines
1.5 KiB
JavaScript
const { Uint8ArrayEncoder } = require("./utils");
|
|
const { getAESSecretKey, decryptAESBlock } = require("./AES");
|
|
|
|
class DecryptorV4 {
|
|
static BLOCK_SIZE = 0x100000 /* data size */ + 0x10 /* padding */;
|
|
|
|
/**
|
|
* Derive key from a given seed (user uuid 2)
|
|
* @param {string} encryptionSeed
|
|
*/
|
|
constructor(encryptionSeed) {
|
|
this.aesKey = getAESSecretKey(encryptionSeed, null);
|
|
}
|
|
|
|
/**
|
|
* Detect if encryption is supported.
|
|
* @param {Uint8Array} fileBody File body for detection
|
|
*/
|
|
static detect(fileBody) {
|
|
const magic = Uint8ArrayEncoder.toUTF8(fileBody.slice(0, 4));
|
|
return magic === "E!04";
|
|
}
|
|
|
|
/**
|
|
* Decrypt a given file.
|
|
* @param {Uint8Array} fileBody file body
|
|
*/
|
|
decryptFile(fileBody) {
|
|
if (!DecryptorV4.detect(fileBody)) {
|
|
throw new Error("file is not using joox v4");
|
|
}
|
|
const view = new DataView(fileBody.buffer, 4, 8);
|
|
const size = (view.getUint32(0, false) << 32) | view.getUint32(4, false);
|
|
if (size < 0) {
|
|
throw new RangeError("unable to decode size");
|
|
}
|
|
const blocks = [];
|
|
let bytesToDecrypt = fileBody.length;
|
|
let i = /* magic */ 4 + /* orig_size */ 8;
|
|
while (bytesToDecrypt > 0) {
|
|
const blockSize = Math.min(DecryptorV4.BLOCK_SIZE, bytesToDecrypt);
|
|
const block = fileBody.subarray(i, i + blockSize);
|
|
const blockDecrypted = decryptAESBlock(this.aesKey, block);
|
|
blocks.push(blockDecrypted);
|
|
|
|
i += blockSize;
|
|
bytesToDecrypt -= blockSize;
|
|
}
|
|
return blocks;
|
|
}
|
|
}
|
|
|
|
module.exports = DecryptorV4;
|