UNPKG

@tgsnake/core

Version:

Pure Telegram MTProto library for nodejs

136 lines (135 loc) 5.55 kB
"use strict"; 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; }, }; }