Browse Source

Added async modPow worker

master
Igor Zhukov 11 years ago
parent
commit
45f3798794
  1. 16
      app/js/lib/bin_utils.js
  2. 17
      app/js/lib/mp_worker.js
  3. 180
      app/js/lib/mtproto.js

16
app/js/lib/bin_utils.js

@ -515,4 +515,18 @@ function pqPrimeLeemon (what) {
// console.log(dT(), 'done', bigInt2str(what, 10), bigInt2str(P, 10), bigInt2str(Q, 10)); // console.log(dT(), 'done', bigInt2str(what, 10), bigInt2str(P, 10), bigInt2str(Q, 10));
return [bytesFromLeemonBigInt(P), bytesFromLeemonBigInt(Q), it]; return [bytesFromLeemonBigInt(P), bytesFromLeemonBigInt(Q), it];
} }
function bytesModPow (x, y, m) {
try {
var xBigInt = str2bigInt(x, 64),
yBigInt = str2bigInt(y, 64),
mBigInt = str2bigInt(bytesToHex(m), 16, 2),
resBigInt = powMod(xBigInt, yBigInt, mBigInt);
return bytesFromHex(bigInt2str(resBigInt, 16));
} catch (e) {}
return bytesFromBigInt(new BigInteger(x).modPow(new BigInteger(y), new BigInteger(m)));
}

17
app/js/lib/mp_worker.js

@ -0,0 +1,17 @@
/*!
* 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]));
}

180
app/js/lib/mtproto.js

@ -85,9 +85,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
var fingerprintBytes = sha1Hash(buffer).slice(-8); var fingerprintBytes = sha1Hash(buffer).slice(-8);
fingerprintBytes.reverse(); fingerprintBytes.reverse();
var fingerprint = new BigInteger(fingerprintBytes).toString(16); publicKeysParsed[bytesToHex(fingerprintBytes)] = {
publicKeysParsed[fingerprint] = {
modulus: keyParsed.modulus, modulus: keyParsed.modulus,
exponent: keyParsed.exponent exponent: keyParsed.exponent
}; };
@ -404,108 +402,132 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
MtpMessageIdGenerator.applyServerTime(auth.serverTime, auth.localTime); 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) { function mtpSendSetClientDhParams(auth) {
var deferred = auth.deferred; var deferred = auth.deferred,
gBytes = bytesFromHex(auth.g.toString(16));
auth.b = new Array(256); auth.b = new Array(256);
MtpSecureRandom.nextBytes(auth.b); MtpSecureRandom.nextBytes(auth.b);
var bBigInt = new BigInteger(auth.b); mtpAsyncModPow(gBytes, auth.b, auth.dhPrime).then(function (gB) {
var dhPrimeBigInt = new BigInteger(auth.dhPrime);
var gB = bytesFromBigInt(bigint(auth.g).modPow(bBigInt, dhPrimeBigInt));
var data = new TLSerialization({mtproto: true}); var data = new TLSerialization({mtproto: true});
data.storeObject({ data.storeObject({
_: 'client_DH_inner_data', _: 'client_DH_inner_data',
nonce: auth.nonce, nonce: auth.nonce,
server_nonce: auth.serverNonce, server_nonce: auth.serverNonce,
retry_id: [0, auth.retry++], retry_id: [0, auth.retry++],
g_b: gB, g_b: gB,
}, 'Client_DH_Inner_Data'); }, 'Client_DH_Inner_Data');
var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes()); var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes());
var encryptedData = aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv); var encryptedData = aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv);
var request = new TLSerialization({mtproto: true}); var request = new TLSerialization({mtproto: true});
request.storeMethod('set_client_DH_params', { request.storeMethod('set_client_DH_params', {
nonce: auth.nonce, nonce: auth.nonce,
server_nonce: auth.serverNonce, server_nonce: auth.serverNonce,
encrypted_data: encryptedData encrypted_data: encryptedData
}); });
console.log(dT(), 'Send set_client_DH_params'); console.log(dT(), 'Send set_client_DH_params');
mtpSendPlainRequest(auth.dcID, request.getBuffer()).then(function (result) { mtpSendPlainRequest(auth.dcID, request.getBuffer()).then(function (result) {
var deserializer = result.data; var deserializer = result.data;
var response = deserializer.fetchObject('Set_client_DH_params_answer'); var response = deserializer.fetchObject('Set_client_DH_params_answer');
if (response._ != 'dh_gen_ok' && response._ != 'dh_gen_retry' && response._ != 'dh_gen_fail') { if (response._ != 'dh_gen_ok' && response._ != 'dh_gen_retry' && response._ != 'dh_gen_fail') {
deferred.reject(new Error('Set_client_DH_params_answer response invalid: ' + response._)); deferred.reject(new Error('Set_client_DH_params_answer response invalid: ' + response._));
return false; return false;
} }
if (!bytesCmp (auth.nonce, response.nonce)) { if (!bytesCmp (auth.nonce, response.nonce)) {
deferred.reject(new Error('Set_client_DH_params_answer nonce mismatch')); deferred.reject(new Error('Set_client_DH_params_answer nonce mismatch'));
return false return false
} }
if (!bytesCmp (auth.serverNonce, response.server_nonce)) { if (!bytesCmp (auth.serverNonce, response.server_nonce)) {
deferred.reject(new Error('Set_client_DH_params_answer server_nonce mismatch')); deferred.reject(new Error('Set_client_DH_params_answer server_nonce mismatch'));
return false; return false;
} }
var bBigInt = new BigInteger(auth.b); mtpAsyncModPow(auth.gA, auth.b, auth.dhPrime).then(function (authKey) {
var dhPrimeBigInt = new BigInteger(auth.dhPrime); var authKeyHash = sha1Hash(authKey),
authKeyAux = authKeyHash.slice(0, 8),
authKeyID = authKeyHash.slice(-8);
var authKey = bytesFromBigInt((new BigInteger(auth.gA)).modPow(bBigInt, dhPrimeBigInt)), console.log(dT(), 'Got Set_client_DH_params_answer', response._);
authKeyHash = sha1Hash(authKey), switch (response._) {
authKeyAux = authKeyHash.slice(0, 8), case 'dh_gen_ok':
authKeyID = authKeyHash.slice(-8); var newNonceHash1 = sha1Hash(auth.newNonce.concat([1], authKeyAux)).slice(-16);
console.log(dT(), 'Got Set_client_DH_params_answer', response._); if (!bytesCmp(newNonceHash1, response.new_nonce_hash1)) {
switch (response._) { deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash1 mismatch'));
case 'dh_gen_ok': return false;
var newNonceHash1 = sha1Hash(auth.newNonce.concat([1], authKeyAux)).slice(-16); }
if (!bytesCmp(newNonceHash1, response.new_nonce_hash1)) { var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8));
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash1 mismatch')); // console.log('Auth successfull!', authKeyID, authKey, serverSalt);
return false;
}
var serverSalt = bytesXor(auth.newNonce.slice(0, 8), auth.serverNonce.slice(0, 8)); auth.authKeyID = authKeyID;
// console.log('Auth successfull!', authKeyID, authKey, serverSalt); auth.authKey = authKey;
auth.serverSalt = serverSalt;
auth.authKeyID = authKeyID; deferred.resolve(auth);
auth.authKey = authKey; break;
auth.serverSalt = serverSalt;
deferred.resolve(auth); case 'dh_gen_retry':
break; var newNonceHash2 = sha1Hash(auth.newNonce.concat([2], authKeyAux)).slice(-16);
if (!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash2 mismatch'));
return false;
}
case 'dh_gen_retry': return mtpSendSetClientDhParams(auth);
var newNonceHash2 = sha1Hash(auth.newNonce.concat([2], authKeyAux)).slice(-16);
if (!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash2 mismatch'));
return false;
}
return mtpSendSetClientDhParams(auth); case 'dh_gen_fail':
var newNonceHash3 = sha1Hash(auth.newNonce.concat([3], authKeyAux)).slice(-16);
if (!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash3 mismatch'));
return false;
}
case 'dh_gen_fail': deferred.reject(new Error('Set_client_DH_params_answer fail'));
var newNonceHash3 = sha1Hash(auth.newNonce.concat([3], authKeyAux)).slice(-16); return false;
if (!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash3 mismatch'));
return false;
} }
}, function (error) {
deferred.reject(new Error('Set_client_DH_params_answer fail')); deferred.reject(error);
return false; })
} }, function (error) {
deferred.reject(error);
});
}, function (error) { }, function (error) {
deferred.reject(error); deferred.reject(error);
}); })
}; };
var cached = {}; var cached = {};

Loading…
Cancel
Save