UNPKG

@runejs/core

Version:

Core logging, networking, and buffer functionality for RuneJS applications.

111 lines 5.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Xtea = void 0; const tslib_1 = require("tslib"); const path_1 = tslib_1.__importDefault(require("path")); const fs_1 = tslib_1.__importDefault(require("fs")); const logger_1 = require("../logger"); const buffer_1 = require("../buffer"); const toInt = value => value | 0; class Xtea { static loadKeys(xteaConfigPath) { var _a; if (!fs_1.default.existsSync(xteaConfigPath)) { logger_1.logger.error(`Error loading XTEA keys: ${xteaConfigPath} was not found.`); return null; } const stats = fs_1.default.statSync(xteaConfigPath); if (!stats.isDirectory()) { logger_1.logger.error(`Error loading XTEA keys: ${xteaConfigPath} is not a directory.`); return null; } const xteaKeys = new Map(); const xteaFileNames = fs_1.default.readdirSync(xteaConfigPath); for (const fileName of xteaFileNames) { try { const gameVersionString = fileName.substring(0, fileName.indexOf('.json')); if (!gameVersionString) { logger_1.logger.error(`Error loading XTEA config file ${fileName}: No game version supplied.`); continue; } const gameVersion = Number(gameVersionString); if (!gameVersion || isNaN(gameVersion)) { logger_1.logger.error(`Error loading XTEA config file ${fileName}: Invalid game version supplied.`); continue; } const fileContent = fs_1.default.readFileSync(path_1.default.join(xteaConfigPath, fileName), 'utf-8'); const xteaConfigList = JSON.parse(fileContent); if (!(xteaConfigList === null || xteaConfigList === void 0 ? void 0 : xteaConfigList.length)) { logger_1.logger.error(`Error loading XTEA config file ${fileName}: File is empty.`); continue; } for (const xteaConfig of xteaConfigList) { if (!(xteaConfig === null || xteaConfig === void 0 ? void 0 : xteaConfig.name) || !((_a = xteaConfig === null || xteaConfig === void 0 ? void 0 : xteaConfig.key) === null || _a === void 0 ? void 0 : _a.length)) { continue; } const { name: fileName, key } = xteaConfig; let fileKeys = []; if (xteaKeys.has(fileName)) { fileKeys = xteaKeys.get(fileName); } fileKeys.push({ gameVersion, key }); xteaKeys.set(fileName, fileKeys); } } catch (error) { logger_1.logger.error(`Error loading XTEA config file ${fileName}:`, error); } } return xteaKeys; } static validKeys(keys) { return (keys === null || keys === void 0 ? void 0 : keys.length) === 4 && (keys[0] !== 0 || keys[1] !== 0 || keys[2] !== 0 || keys[3] !== 0); } // @TODO unit testing static encrypt(input, keys, length) { const encryptedBuffer = new buffer_1.ByteBuffer(length); const chunks = length / 8; input.readerIndex = 0; for (let i = 0; i < chunks; i++) { let v0 = input.get('int'); let v1 = input.get('int'); let sum = 0; const delta = -0x61c88647; let rounds = 32; while (rounds-- > 0) { v0 += ((sum + keys[sum & 3]) ^ (v1 + ((v1 >>> 5) ^ (v1 << 4)))); sum += delta; v1 += ((v0 + ((v0 >>> 5) ^ (v0 << 4))) ^ (keys[(sum >>> 11) & 3] + sum)); } encryptedBuffer.put(v0, 'int'); encryptedBuffer.put(v1, 'int'); } return encryptedBuffer.flipWriter(); } // @TODO unit testing static decrypt(input, keys, length) { if (!(keys === null || keys === void 0 ? void 0 : keys.length)) { return input; } const output = new buffer_1.ByteBuffer(length); const numBlocks = Math.floor(length / 8); for (let block = 0; block < numBlocks; block++) { let v0 = input.get('int'); let v1 = input.get('int'); let sum = 0x9E3779B9 * 32; for (let i = 0; i < 32; i++) { v1 -= ((toInt(v0 << 4) ^ toInt(v0 >>> 5)) + v0) ^ (sum + keys[(sum >>> 11) & 3]); v1 = toInt(v1); sum -= 0x9E3779B9; v0 -= ((toInt(v1 << 4) ^ toInt(v1 >>> 5)) + v1) ^ (sum + keys[sum & 3]); v0 = toInt(v0); } output.put(v0, 'int'); output.put(v1, 'int'); } input.copy(output, output.writerIndex, input.readerIndex); return output; } } exports.Xtea = Xtea; //# sourceMappingURL=xtea.js.map