From a3a08806ad03af7a0ebb0fd1068553c95748fc5d Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Sat, 5 Jul 2014 00:01:23 +0400 Subject: [PATCH] Moved all crypto tasks to separate service --- app/js/lib/aes_worker.js | 26 ----- app/js/lib/crypto_worker.js | 47 +++++++++ app/js/lib/mp_worker.js | 17 ---- app/js/lib/mtproto.js | 188 ++++-------------------------------- app/js/lib/ng_utils.js | 95 ++++++++++++++++++ app/js/lib/pq_worker.js | 18 ---- app/js/lib/sha1_worker.js | 18 ---- 7 files changed, 159 insertions(+), 250 deletions(-) delete mode 100644 app/js/lib/aes_worker.js create mode 100644 app/js/lib/crypto_worker.js delete mode 100644 app/js/lib/mp_worker.js delete mode 100644 app/js/lib/pq_worker.js delete mode 100644 app/js/lib/sha1_worker.js diff --git a/app/js/lib/aes_worker.js b/app/js/lib/aes_worker.js deleted file mode 100644 index f40ce525..00000000 --- a/app/js/lib/aes_worker.js +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * Webogram v0.2 - messaging web application for MTProto - * https://github.com/zhukov/webogram - * Copyright (C) 2014 Igor Zhukov - * https://github.com/zhukov/webogram/blob/master/LICENSE - */ - -importScripts( - '../../vendor/console-polyfill/console-polyfill.js', - 'bin_utils.js', - '../../vendor/jsbn/jsbn_combined.js', - '../../vendor/cryptoJS/crypto.js' -); - -onmessage = function (e) { - // console.log('AES worker in', e.data); - var taskID = e.data.taskID, - result; - - if (e.data.task == 'encrypt') { - result = aesEncrypt(e.data.bytes, e.data.keyBytes, e.data.ivBytes); - } else { - result = aesDecrypt(e.data.encryptedBytes, e.data.keyBytes, e.data.ivBytes); - } - postMessage({taskID: taskID, result: result}); -} diff --git a/app/js/lib/crypto_worker.js b/app/js/lib/crypto_worker.js new file mode 100644 index 00000000..b53e6f20 --- /dev/null +++ b/app/js/lib/crypto_worker.js @@ -0,0 +1,47 @@ +/*! + * Webogram v0.2 - messaging web application for MTProto + * https://github.com/zhukov/webogram + * Copyright (C) 2014 Igor Zhukov + * https://github.com/zhukov/webogram/blob/master/LICENSE + */ + +importScripts( + '../../vendor/console-polyfill/console-polyfill.js', + 'bin_utils.js', + '../../vendor/jsbn/jsbn_combined.js', + '../../vendor/leemon_bigint/bigint.js', + '../../vendor/closure/long.js', + '../../vendor/cryptoJS/crypto.js' +); + +onmessage = function (e) { + var taskID = e.data.taskID, + result; + + switch (e.data.task) { + case 'factorize': + result = pqPrimeFactorization(e.data.bytes); + break; + + case 'mod-pow': + result = bytesModPow(e.data.x, e.data.y, e.data.m); + break; + + case 'sha1-hash': + result = sha1Hash(e.data.bytes); + break; + + case 'aes-encrypt': + result = aesEncrypt(e.data.bytes, e.data.keyBytes, e.data.ivBytes); + break; + + case 'aes-decrypt': + result = aesDecrypt(e.data.encryptedBytes, e.data.keyBytes, e.data.ivBytes); + break; + + default: + throw new Error('Unknown task: ' + e.data.task); + } + + postMessage({taskID: taskID, result: result}); +} diff --git a/app/js/lib/mp_worker.js b/app/js/lib/mp_worker.js deleted file mode 100644 index fa0582bb..00000000 --- a/app/js/lib/mp_worker.js +++ /dev/null @@ -1,17 +0,0 @@ -/*! - * Webogram v0.2 - messaging web application for MTProto - * https://github.com/zhukov/webogram - * Copyright (C) 2014 Igor Zhukov - * https://github.com/zhukov/webogram/blob/master/LICENSE - */ - -importScripts( - '../../vendor/console-polyfill/console-polyfill.js', - 'bin_utils.js', - '../../vendor/leemon_bigint/bigint.js', - '../../vendor/jsbn/jsbn_combined.js' -); - -onmessage = function (e) { - postMessage(bytesModPow(e.data[0], e.data[1], e.data[2])); -} diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 2dbbf2aa..c4a8a3a8 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -166,7 +166,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) }; }) -.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpMessageIdGenerator, $http, $q, $timeout) { +.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpMessageIdGenerator, CryptoWorker, $http, $q, $timeout) { function mtpSendPlainRequest (dcID, requestBuffer) { var requestLength = requestBuffer.byteLength, @@ -255,30 +255,15 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) } console.log(dT(), 'PQ factorization start', auth.pq); - if (!!window.Worker/* && false*/) { - var worker = new Worker('js/lib/pq_worker.js'), - curRetry = auth.pqRetry, - canceled = false; - - worker.onmessage = function (e) { - auth.p = e.data[0]; - auth.q = e.data[1]; - console.log(dT(), 'PQ factorization done', e.data[2]); - mtpSendReqDhParams(auth); - }; - worker.onerror = function(error) { - console.log('Worker error', error, error.stack); - deferred.reject(error); - }; - worker.postMessage(auth.pq); - } else { - var pAndQ = pqPrimeFactorization(auth.pq); + CryptoWorker.factorize(auth.pq).then(function (pAndQ) { auth.p = pAndQ[0]; auth.q = pAndQ[1]; - console.log(dT(), 'PQ factorization done', pAndQ[2]); mtpSendReqDhParams(auth); - } + }, function (error) { + console.log('Worker error', error, error.stack); + deferred.reject(error); + }); }, function (error) { console.log(dT(), 'req_pq error', error.message); deferred.reject(error); @@ -291,10 +276,6 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) function mtpSendReqDhParams (auth) { - alert('send req dh'); - alert(auth.p); - alert(auth.q); - var deferred = auth.deferred; auth.newNonce = new Array(32); @@ -409,30 +390,6 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) MtpMessageIdGenerator.applyServerTime(auth.serverTime, auth.localTime); }; - function mtpAsyncModPow (x, y, m) { - console.log(dT(), 'modPow start'); - if (!window.Worker) { - var result = bytesModPow(x, y, m); - console.log(dT(), 'sync modPow done'); - return $q.when(result); - } - - var deferred = $q.defer(), - worker = new Worker('js/lib/mp_worker.js'); - - worker.onmessage = function (e) { - console.log(dT(), 'async modPow done'); - deferred.resolve(e.data); - }; - worker.onerror = function(error) { - console.log('Worker error', error, error.stack); - deferred.reject(error); - }; - worker.postMessage([x, y, m]); - - return deferred.promise; - } - function mtpSendSetClientDhParams(auth) { var deferred = auth.deferred, gBytes = bytesFromHex(auth.g.toString(16)); @@ -440,7 +397,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) auth.b = new Array(256); MtpSecureRandom.nextBytes(auth.b); - mtpAsyncModPow(gBytes, auth.b, auth.dhPrime).then(function (gB) { + CryptoWorker.modPow(gBytes, auth.b, auth.dhPrime).then(function (gB) { var data = new TLSerialization({mtproto: true}); data.storeObject({ @@ -482,7 +439,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) return false; } - mtpAsyncModPow(auth.gA, auth.b, auth.dhPrime).then(function (authKey) { + CryptoWorker.modPow(auth.gA, auth.b, auth.dhPrime).then(function (authKey) { var authKeyHash = sha1Hash(authKey), authKeyAux = authKeyHash.slice(0, 8), authKeyID = authKeyHash.slice(-8); @@ -572,107 +529,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) }) -.factory('MtpAesService', function ($q) { - if (!window.Worker || true) { - return { - encrypt: function (bytes, keyBytes, ivBytes) { - return $q.when(aesEncrypt(bytes, keyBytes, ivBytes)); - }, - decrypt: function (encryptedBytes, keyBytes, ivBytes) { - return $q.when(aesDecrypt(encryptedBytes, keyBytes, ivBytes)); - } - }; - } - - var worker = new Worker('js/lib/aes_worker.js'), - taskID = 0, - awaiting = {}; - - worker.onmessage = function (e) { - var deferred = awaiting[e.data.taskID]; - if (deferred !== undefined) { - deferred.resolve(e.data.result); - delete awaiting[e.data.taskID]; - } - // console.log('AES worker message', e.data, deferred); - }; - worker.onerror = function(error) { - console.log('AES Worker error', error, error.stack); - }; - - return { - encrypt: function (bytes, keyBytes, ivBytes) { - var deferred = $q.defer(); - - awaiting[taskID] = deferred; - - // console.log('AES post message', {taskID: taskID, task: 'encrypt', bytes: bytes, keyBytes: keyBytes, ivBytes: ivBytes}) - worker.postMessage({taskID: taskID, task: 'encrypt', bytes: bytes, keyBytes: keyBytes, ivBytes: ivBytes}); - - taskID++; - - return deferred.promise; - }, - decrypt: function (encryptedBytes, keyBytes, ivBytes) { - var deferred = $q.defer(); - - awaiting[taskID] = deferred; - worker.postMessage({taskID: taskID, task: 'decrypt', encryptedBytes: encryptedBytes, keyBytes: keyBytes, ivBytes: ivBytes}); - - taskID++; - - return deferred.promise; - } - } -}) - -.factory('MtpSha1Service', function ($q) { - if (!window.Worker || true) { - return { - hash: function (bytes) { - var deferred = $q.defer(); - - setTimeout(function () { - deferred.resolve(sha1Hash(bytes)); - }, 0); - - return deferred.promise; - } - }; - } - - var worker = new Worker('js/lib/sha1_worker.js'), - taskID = 0, - awaiting = {}; - - worker.onmessage = function (e) { - var deferred = awaiting[e.data.taskID]; - if (deferred !== undefined) { - deferred.resolve(e.data.result); - delete awaiting[e.data.taskID]; - } - // console.log('sha1 got message', e.data, deferred); - }; - worker.onerror = function(error) { - console.log('SHA-1 Worker error', error, error.stack); - }; - - return { - hash: function (bytes) { - var deferred = $q.defer(); - - awaiting[taskID] = deferred; - // console.log(11, taskID, bytes); - worker.postMessage({taskID: taskID, bytes: bytes}); - - taskID++; - - return deferred.promise; - } - } -}) - -.factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, Storage, $http, $q, $timeout, $interval, $rootScope) { +.factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, Storage, CryptoWorker, $http, $q, $timeout, $interval, $rootScope) { var updatesProcessor, iii = 0, @@ -928,10 +785,10 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) x = isOut ? 0 : 8; var promises = { - sha1a: MtpSha1Service.hash(msgKey.concat(authKey.slice(x, x + 32))), - sha1b: MtpSha1Service.hash(authKey.slice(32 + x, 48 + x).concat(msgKey, authKey.slice(48 + x, 64 + x))), - sha1c: MtpSha1Service.hash(authKey.slice(64 + x, 96 + x).concat(msgKey)), - sha1d: MtpSha1Service.hash(msgKey.concat(authKey.slice(96 + x, 128 + x))) + sha1a: CryptoWorker.sha1Hash(msgKey.concat(authKey.slice(x, x + 32))), + sha1b: CryptoWorker.sha1Hash(authKey.slice(32 + x, 48 + x).concat(msgKey, authKey.slice(48 + x, 64 + x))), + sha1c: CryptoWorker.sha1Hash(authKey.slice(64 + x, 96 + x).concat(msgKey)), + sha1d: CryptoWorker.sha1Hash(msgKey.concat(authKey.slice(96 + x, 128 + x))) }; return $q.all(promises).then(function (result) { @@ -1173,17 +1030,10 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) MtpNetworker.prototype.getEncryptedMessage = function (bytes) { var self = this; - // console.log('enc', bytes); - - return MtpSha1Service.hash(bytes).then(function (bytesHash) { - // console.log('bytesHash', bytesHash); + return CryptoWorker.sha1Hash(bytes).then(function (bytesHash) { var msgKey = bytesHash.slice(-16); return self.getMsgKeyIv(msgKey, true).then(function (keyIv) { - // console.log('keyIv', keyIv); - // console.time('Aes encrypt ' + bytes.length + ' bytes'); - return MtpAesService.encrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) { - // console.log('encryptedBytes', encryptedBytes); - // console.timeEnd('Aes encrypt ' + bytes.length + ' bytes'); + return CryptoWorker.aesEncrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) { return { bytes: encryptedBytes, msgKey: msgKey @@ -1195,11 +1045,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) MtpNetworker.prototype.getDecryptedMessage = function (msgKey, encryptedData) { return this.getMsgKeyIv(msgKey, false).then(function (keyIv) { - // console.time('Aes decrypt ' + encryptedData.length + ' bytes'); - return MtpAesService.decrypt(encryptedData, keyIv[0], keyIv[1])/*.then(function (a) { - console.timeEnd('Aes decrypt ' + encryptedData.length + ' bytes'); - return a; - })*/; + return CryptoWorker.aesDecrypt(encryptedData, keyIv[0], keyIv[1]); }); }; @@ -1275,7 +1121,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var offset = deserializer.getOffset(); - return MtpSha1Service.hash(dataWithPadding.slice(0, offset)).then(function (dataHashed) { + return CryptoWorker.sha1Hash(dataWithPadding.slice(0, offset)).then(function (dataHashed) { if (!bytesCmp(msgKey, dataHashed.slice(-16))) { throw new Error('server msgKey mismatch'); } diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js index a4b72722..7eef7698 100644 --- a/app/js/lib/ng_utils.js +++ b/app/js/lib/ng_utils.js @@ -549,3 +549,98 @@ angular.module('izhukov.utils', []) }; }) +.service('CryptoWorker', function ($timeout, $q) { + + var worker = window.Worker && new Worker('js/lib/crypto_worker.js') || false, + taskID = 0, + awaiting = {}; + + if (worker) { + worker.onmessage = function (e) { + var deferred = awaiting[e.data.taskID]; + if (deferred !== undefined) { + console.log(dT(), 'CW done'); + deferred.resolve(e.data.result); + delete awaiting[e.data.taskID]; + } + }; + + worker.onerror = function(error) { + console.log('CW error', error, error.stack); + }; + } + + function performTaskWorker (task, params) { + console.log(dT(), 'CW start', task); + var deferred = $q.defer(); + + awaiting[taskID] = deferred; + + params.task = task; + params.taskID = taskID; + worker.postMessage(params); + + taskID++; + + return deferred.promise; + } + + return { + sha1Hash: function (bytes) { + if (worker && false) { // due overhead for data transfer + return performTaskWorker ('sha1-hash', {bytes: bytes}); + } + return $timeout(function () { + return sha1Hash(bytes); + }); + }, + aesEncrypt: function (bytes, keyBytes, ivBytes) { + if (worker && false) { // due overhead for data transfer + return performTaskWorker('aes-encrypt', { + bytes: bytes, + keyBytes: keyBytes, + ivBytes: ivBytes + }); + } + return $timeout(function () { + return aesEncrypt(bytes, keyBytes, ivBytes); + }); + }, + aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) { + if (worker && false) { // due overhead for data transfer + return performTaskWorker('aes-decrypt', { + encryptedBytes: encryptedBytes, + keyBytes: keyBytes, + ivBytes: ivBytes + }); + } + return $timeout(function () { + return aesDecrypt(encryptedBytes, keyBytes, ivBytes); + }); + }, + factorize: function (bytes) { + if (worker) { + return performTaskWorker('factorize', {bytes: bytes}); + } + return $timeout(function () { + return pqPrimeFactorization(bytes); + }); + }, + modPow: function (x, y, m) { + if (worker) { + return performTaskWorker('mod-pow', { + x: x, + y: y, + m: m + }); + } + return $timeout(function () { + return bytesModPow(x, y, m); + }); + }, + }; +}) + + + + diff --git a/app/js/lib/pq_worker.js b/app/js/lib/pq_worker.js deleted file mode 100644 index 13ea5d73..00000000 --- a/app/js/lib/pq_worker.js +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Webogram v0.2 - messaging web application for MTProto - * https://github.com/zhukov/webogram - * Copyright (C) 2014 Igor Zhukov - * https://github.com/zhukov/webogram/blob/master/LICENSE - */ - -importScripts( - '../../vendor/console-polyfill/console-polyfill.js', - 'bin_utils.js', - '../../vendor/leemon_bigint/bigint.js', - '../../vendor/closure/long.js', - '../../vendor/jsbn/jsbn_combined.js' -); - -onmessage = function (e) { - postMessage(pqPrimeFactorization(e.data)); -} diff --git a/app/js/lib/sha1_worker.js b/app/js/lib/sha1_worker.js deleted file mode 100644 index dea77604..00000000 --- a/app/js/lib/sha1_worker.js +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Webogram v0.2 - messaging web application for MTProto - * https://github.com/zhukov/webogram - * Copyright (C) 2014 Igor Zhukov - * https://github.com/zhukov/webogram/blob/master/LICENSE - */ - -importScripts( - '../../vendor/console-polyfill/console-polyfill.js', - 'bin_utils.js', - '../../vendor/cryptoJS/crypto.js' -); - -onmessage = function (e) { - var taskID = e.data.taskID; - - postMessage({taskID: taskID, result: sha1Hash(e.data.bytes)}); -}