@tgsnake/core
Version:
Pure Telegram MTProto library for nodejs
136 lines (135 loc) • 5.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ige256Encrypt = ige256Encrypt;
exports.ige256Decrypt = ige256Decrypt;
exports.ctr256Cipher = ctr256Cipher;
exports.xor = xor;
exports.AES = AES;
const platform_node_js_1 = require("../platform.node.js");
const Logger_js_1 = require("../Logger.js");
const helpers_js_1 = require("../helpers.js");
function ige256Encrypt(data, key, iv) {
Logger_js_1.Logger.debug(`[4] Encrypting ${platform_node_js_1.Buffer.byteLength(data)} bytes data with AES-256-IGE`);
const pad = (0, helpers_js_1.mod)(platform_node_js_1.Buffer.byteLength(data), 16);
if (pad) {
data = platform_node_js_1.Buffer.concat([
data,
platform_node_js_1.crypto.randomBytes(16 - pad),
]);
}
return ige(data, key, iv, true);
}
function ige256Decrypt(data, key, iv) {
Logger_js_1.Logger.debug(`[5] Decrypting ${platform_node_js_1.Buffer.byteLength(data)} bytes data with AES-256-IGE`);
return ige(data, key, iv, false);
}
function ctr256Cipher(key, iv) {
if (platform_node_js_1.where === 'Browser') {
const cipher = new platform_node_js_1.aesjs.ModeOfOperation.ctr(key, new platform_node_js_1.aesjs.Counter(Uint8Array.from(iv)));
return (data) => {
Logger_js_1.Logger.debug(`[140] Cryptograph ${platform_node_js_1.Buffer.byteLength(data)} bytes data with AES-256-CTR`);
return platform_node_js_1.Buffer.from(cipher.encrypt(data));
};
}
try {
const cipher = platform_node_js_1.crypto.createCipheriv('AES-256-CTR', key, iv);
return (data) => {
Logger_js_1.Logger.debug(`[140] Cryptograph ${platform_node_js_1.Buffer.byteLength(data)} bytes data with AES-256-CTR`);
return platform_node_js_1.Buffer.from(cipher.update(data));
};
}
catch (_error) {
const cipher = ctr(key, iv);
return (data) => {
Logger_js_1.Logger.debug(`[140] Cryptograph ${platform_node_js_1.Buffer.byteLength(data)} bytes data with AES-256-CTR`);
return platform_node_js_1.Buffer.from(cipher.update(data));
};
}
}
function xor(a, b) {
return (0, helpers_js_1.bigintToBuffer)(BigInt((0, helpers_js_1.bufferToBigint)(a, false) ^ (0, helpers_js_1.bufferToBigint)(b, false)), platform_node_js_1.Buffer.byteLength(a), false);
}
function AES(key) {
const iv = platform_node_js_1.Buffer.alloc(0);
if (platform_node_js_1.where === 'Browser' || platform_node_js_1.where === 'Deno') {
const cipher = new platform_node_js_1.aesjs.ModeOfOperation.ecb(key);
return {
encrypt(data) {
return platform_node_js_1.Buffer.from(cipher.encrypt(data));
},
decrypt(data) {
return platform_node_js_1.Buffer.from(cipher.decrypt(data));
},
};
}
else {
const cipher = platform_node_js_1.crypto.createCipheriv('aes-256-ecb', key, iv);
const decipher = platform_node_js_1.crypto.createDecipheriv('aes-256-ecb', key, iv);
cipher.setAutoPadding(false);
decipher.setAutoPadding(false);
return {
encrypt(data) {
return platform_node_js_1.Buffer.from(cipher.update(data));
},
decrypt(data) {
return platform_node_js_1.Buffer.from(decipher.update(data));
},
};
}
}
function ige(data, key, iv, encrypt) {
const cipher = AES(key);
let iv1 = iv.subarray(0, 16);
let iv2 = iv.subarray(16, 32);
const temp = [];
for (const i of (0, helpers_js_1.range)(0, platform_node_js_1.Buffer.byteLength(data), 16)) {
temp.push(data.subarray(i, i + 16));
}
if (encrypt) {
for (let i = 0; i < temp.length; i++) {
const chunk = temp[i];
iv1 = temp[i] = xor(cipher.encrypt(xor(chunk, iv1)), iv2);
iv2 = chunk;
}
}
else {
for (let i = 0; i < temp.length; i++) {
const chunk = temp[i];
iv2 = temp[i] = xor(cipher.decrypt(xor(chunk, iv2)), iv1);
iv1 = chunk;
}
}
return platform_node_js_1.Buffer.concat(temp);
}
function ctr(key, iv, state = platform_node_js_1.Buffer.alloc(1)) {
const cipher = AES(platform_node_js_1.Buffer.from(key));
const _iv = platform_node_js_1.Buffer.from(iv);
let chunk = platform_node_js_1.Buffer.from(cipher.encrypt(iv));
return {
update: (data) => {
const out = platform_node_js_1.Buffer.from(data);
for (const i of (0, helpers_js_1.range)(0, platform_node_js_1.Buffer.byteLength(data), 16)) {
for (const j of (0, helpers_js_1.range)(0, Math.min(platform_node_js_1.Buffer.byteLength(data) - i, 16))) {
out[i + j] ^= chunk[state[0]];
state[0] += 1;
if (state[0] >= 16) {
state[0] = 0;
}
if (state[0] === 0) {
for (const k of (0, helpers_js_1.range)(15, -1, -1)) {
if (_iv[k] === 255) {
_iv[k] = 0;
}
else {
_iv[k] += 1;
break;
}
}
chunk = cipher.encrypt(_iv);
}
}
}
return out;
},
};
}