UNPKG

madeline-ton

Version:

Pure JS client-side implementation of the Telegram TON blockchain protocol

206 lines (178 loc) 6.29 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _crypto = require("../crypto-sync/crypto"); var _poly = require("../crypto-sync/poly"); var _tools = require("../tools"); /** * Webcrypto implementaition * * Copyright 2016-2019 Daniil Gentili * (https://daniil.it) * This file is part of MadelineNode. * MadelineNode is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * MadelineNode is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU General Public License along with MadelineNode. * If not, see <http://www.gnu.org/licenses/>. * * @author Daniil Gentili <daniil@daniil.it> * @copyright 2016-2019 Daniil Gentili <daniil@daniil.it> * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 */ var CtrProcessor = /*#__PURE__*/ function () { function CtrProcessor() { (0, _classCallCheck2["default"])(this, CtrProcessor); } (0, _createClass2["default"])(CtrProcessor, [{ key: "init", /** * Init processor * @param {Uint32Array} iv * @param {Uint32Array} key */ value: function init(key, iv) { var _this = this; this.name = "AES-CTR"; this.by = 0; this.counter = iv; this.length = 16; this.leftover = new Uint8Array(0); return _poly.windowObject.crypto.subtle.importKey("raw", key, "AES-CTR", false, ["encrypt"]).then(function (key) { _this.key = key; return _this; }); } /** * Encrypt data * @param {ArrayBufferView} data Data to encrypt * @returns {ArrayBuffer} */ }, { key: "process", value: function process(data) { // Turn block cipher into stream cypher by padding + reusing the last partial block var lengthOrig = data.byteLength; var lengthCombined = lengthOrig; var offset = 0; //console.log(data) if (offset = this.leftover.byteLength) { lengthCombined += offset; var newData = new Uint8Array(lengthCombined + (0, _tools.posMod)(-lengthCombined, 16)); newData.set(this.leftover); newData.set(new Uint8Array(data.buffer), offset); data = newData.buffer; } else { data = (0, _crypto.pad)(data, 16); } //console.log(new Uint8Array(data)) (0, _crypto.incCounter)(this.counter, this.by); this.by = Math.floor(lengthCombined / 16); this.leftover = new Uint8Array(data.slice(this.by * 16, lengthCombined)); //console.log(this.by, this.leftover) return _poly.windowObject.crypto.subtle.encrypt(this, this.key, data).then(function (res) { return res.slice(offset, offset + lengthOrig); }); } }, { key: "close", value: function close() {} }]); return CtrProcessor; }(); /** * * @param {Uint32Array} key * @param {Uint32Array} data * @param {number} offset * @param {Uint32Array} iv1 * @param {Uint32Array} iv2 * @returns {ArrayBuffer} */ var processIgeEncrypt = function processIgeEncrypt(key, data, offset, iv1, iv2) { // I could've also used CBC, but webcrypto's CBC implementation pads the output by default. // This would be fine in itself if it weren't for the fact that webcrypto is forced to do one extra (& useless) AES round per block // CTR doesn't pad the output, so it's perfect. var next = offset + 4; var block = data.slice(offset, next); return _poly.windowObject.crypto.subtle.encrypt({ name: 'AES-CTR', counter: block.map(function (v, i) { return v ^ iv1[i]; }), length: 16 }, key, iv2).then(function (newBlock) { newBlock = new Uint32Array(newBlock); data.set(newBlock, offset); if (next < data.length) { return processIgeEncrypt(key, data, next, newBlock, block); } return data.buffer; }); }; /** * Webcrypto implementation */ var CryptoWebCrypto = /*#__PURE__*/ function () { function CryptoWebCrypto() { (0, _classCallCheck2["default"])(this, CryptoWebCrypto); } (0, _createClass2["default"])(CryptoWebCrypto, [{ key: "sha1", /** * SHA1 * @param {BufferSource} data Data to hash * @returns {ArrayBuffer} */ value: function sha1(data) { return _poly.windowObject.crypto.subtle.digest('SHA-1', data); } /** * SHA256 * @param {BufferSource} data Data to hash * @returns {ArrayBuffer} */ }, { key: "sha256", value: function sha256(data) { return _poly.windowObject.crypto.subtle.digest('SHA-256', data); } /** * Get continuous CTR processor * @param {Uint32Array} iv * @param {Uint32Array} key * @returns CtrProcessor */ }, { key: "getCtr", value: function getCtr(key, iv) { return new CtrProcessor().init(key, iv); } /** * Encrypt data using AES IGE * @param {Uint32Array} data Data * @param {Uint32Array} key Key * @param {Uint32Array} iv IV * @returns {ArrayBuffer} */ }, { key: "igeEncrypt", value: function igeEncrypt(data, key, iv) { // Implement AES IGE using AES CTR and some additional XOR-ing // Use native WebCrypto for greater AES performance // Unfortunately, I can't implement native AES IGE decryption because webcrypto assumes PKCS padding for the cyphertext return _poly.windowObject.crypto.subtle.importKey("raw", key.buffer, "AES-CTR", false, ["encrypt"]).then(function (key) { return processIgeEncrypt(key, data, 0, iv.subarray(0, 4), iv.subarray(4, 8)); }); } }]); return CryptoWebCrypto; }(); var _default = CryptoWebCrypto; exports["default"] = _default;