Browse Source

Moved all crypto tasks to separate service

master
Igor Zhukov 10 years ago
parent
commit
a3a08806ad
  1. 26
      app/js/lib/aes_worker.js
  2. 47
      app/js/lib/crypto_worker.js
  3. 17
      app/js/lib/mp_worker.js
  4. 188
      app/js/lib/mtproto.js
  5. 95
      app/js/lib/ng_utils.js
  6. 18
      app/js/lib/pq_worker.js
  7. 18
      app/js/lib/sha1_worker.js

26
app/js/lib/aes_worker.js

@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
/*!
* Webogram v0.2 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* 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});
}

47
app/js/lib/crypto_worker.js

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
/*!
* Webogram v0.2 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* 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});
}

17
app/js/lib/mp_worker.js

@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
/*!
* Webogram v0.2 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* 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]));
}

188
app/js/lib/mtproto.js

@ -166,7 +166,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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']) @@ -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');
}

95
app/js/lib/ng_utils.js

@ -549,3 +549,98 @@ angular.module('izhukov.utils', []) @@ -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);
});
},
};
})

18
app/js/lib/pq_worker.js

@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
/*!
* Webogram v0.2 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* 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));
}

18
app/js/lib/sha1_worker.js

@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
/*!
* Webogram v0.2 - messaging web application for MTProto
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* 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)});
}
Loading…
Cancel
Save