Migrate AES to Native Client
Up to 4x faster upload files Up to 2x faster download files
This commit is contained in:
parent
2c49f28b7d
commit
5661533fc4
@ -112,11 +112,11 @@ function bytesXor (bytes1, bytes2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bytesToWords (bytes) {
|
function bytesToWords (bytes) {
|
||||||
var len = bytes.byteLength || bytes.length,
|
|
||||||
words = [], i;
|
|
||||||
if (bytes instanceof ArrayBuffer) {
|
if (bytes instanceof ArrayBuffer) {
|
||||||
bytes = new Uint8Array(bytes);
|
bytes = new Uint8Array(bytes);
|
||||||
}
|
}
|
||||||
|
var len = bytes.length,
|
||||||
|
words = [], i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8);
|
words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8);
|
||||||
}
|
}
|
||||||
@ -156,6 +156,24 @@ function bytesToArrayBuffer (b) {
|
|||||||
return (new Uint8Array(b)).buffer;
|
return (new Uint8Array(b)).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertToArrayBuffer(bytes) {
|
||||||
|
// Be careful with converting subarrays!!
|
||||||
|
if (bytes instanceof ArrayBuffer) {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
if (bytes.buffer !== undefined) {
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
return bytesToArrayBuffer(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToUint8Array(bytes) {
|
||||||
|
if (bytes.buffer !== undefined) {
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
return new Uint8Array(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
function bytesFromArrayBuffer (buffer) {
|
function bytesFromArrayBuffer (buffer) {
|
||||||
var len = buffer.byteLength,
|
var len = buffer.byteLength,
|
||||||
byteView = new Uint8Array(buffer),
|
byteView = new Uint8Array(buffer),
|
||||||
@ -207,25 +225,24 @@ function uintToInt (val) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sha1Hash (bytes) {
|
function sha1HashSync (bytes) {
|
||||||
this.rushaInstance = this.rushaInstance || new Rusha(1024 * 1024);
|
this.rushaInstance = this.rushaInstance || new Rusha(1024 * 1024);
|
||||||
|
|
||||||
// console.log(dT(), 'SHA-1 hash start', bytes.byteLength || bytes.length);
|
// console.log(dT(), 'SHA-1 hash start', bytes.byteLength || bytes.length);
|
||||||
var hashBytes = bytesFromArrayBuffer(rushaInstance.rawDigest(bytes).buffer);
|
var hashBytes = rushaInstance.rawDigest(bytes).buffer;
|
||||||
// console.log(dT(), 'SHA-1 hash finish');
|
// console.log(dT(), 'SHA-1 hash finish');
|
||||||
|
|
||||||
return hashBytes;
|
return hashBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sha1BytesSync (bytes) {
|
||||||
|
return bytesFromArrayBuffer(sha1HashSync(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function rsaEncrypt (publicKey, bytes) {
|
function rsaEncrypt (publicKey, bytes) {
|
||||||
var needPadding = 255 - bytes.length;
|
bytes = addPadding(bytes, 255);
|
||||||
if (needPadding > 0) {
|
|
||||||
var padding = new Array(needPadding);
|
|
||||||
(new SecureRandom()).nextBytes(padding);
|
|
||||||
|
|
||||||
bytes = bytes.concat(padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('RSA encrypt start');
|
// console.log('RSA encrypt start');
|
||||||
var N = new BigInteger(publicKey.modulus, 16),
|
var N = new BigInteger(publicKey.modulus, 16),
|
||||||
@ -233,18 +250,16 @@ function rsaEncrypt (publicKey, bytes) {
|
|||||||
X = new BigInteger(bytes),
|
X = new BigInteger(bytes),
|
||||||
encryptedBigInt = X.modPowInt(E, N),
|
encryptedBigInt = X.modPowInt(E, N),
|
||||||
encryptedBytes = bytesFromBigInt(encryptedBigInt, 256);
|
encryptedBytes = bytesFromBigInt(encryptedBigInt, 256);
|
||||||
|
|
||||||
// console.log('RSA encrypt finish');
|
// console.log('RSA encrypt finish');
|
||||||
|
|
||||||
return encryptedBytes;
|
return encryptedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function aesEncrypt (bytes, keyBytes, ivBytes) {
|
function addPadding(bytes, blockSize) {
|
||||||
|
blockSize = blockSize || 16;
|
||||||
var len = bytes.byteLength || bytes.length;
|
var len = bytes.byteLength || bytes.length;
|
||||||
console.log(dT(), 'AES encrypt start', len/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/);
|
var needPadding = blockSize - (len % blockSize);
|
||||||
|
if (needPadding > 0 && needPadding < blockSize) {
|
||||||
var needPadding = 16 - (len % 16);
|
|
||||||
if (needPadding > 0 && needPadding < 16) {
|
|
||||||
var padding = new Array(needPadding);
|
var padding = new Array(needPadding);
|
||||||
(new SecureRandom()).nextBytes(padding);
|
(new SecureRandom()).nextBytes(padding);
|
||||||
|
|
||||||
@ -255,6 +270,15 @@ function aesEncrypt (bytes, keyBytes, ivBytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function aesEncryptSync (bytes, keyBytes, ivBytes) {
|
||||||
|
var len = bytes.byteLength || bytes.length;
|
||||||
|
|
||||||
|
// console.log(dT(), 'AES encrypt start', len/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/);
|
||||||
|
bytes = addPadding(bytes);
|
||||||
|
|
||||||
var encryptedWords = CryptoJS.AES.encrypt(bytesToWords(bytes), bytesToWords(keyBytes), {
|
var encryptedWords = CryptoJS.AES.encrypt(bytesToWords(bytes), bytesToWords(keyBytes), {
|
||||||
iv: bytesToWords(ivBytes),
|
iv: bytesToWords(ivBytes),
|
||||||
padding: CryptoJS.pad.NoPadding,
|
padding: CryptoJS.pad.NoPadding,
|
||||||
@ -262,15 +286,14 @@ function aesEncrypt (bytes, keyBytes, ivBytes) {
|
|||||||
}).ciphertext;
|
}).ciphertext;
|
||||||
|
|
||||||
var encryptedBytes = bytesFromWords(encryptedWords);
|
var encryptedBytes = bytesFromWords(encryptedWords);
|
||||||
|
// console.log(dT(), 'AES encrypt finish');
|
||||||
console.log(dT(), 'AES encrypt finish');
|
|
||||||
|
|
||||||
return encryptedBytes;
|
return encryptedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function aesDecrypt (encryptedBytes, keyBytes, ivBytes) {
|
function aesDecryptSync (encryptedBytes, keyBytes, ivBytes) {
|
||||||
// console.log('AES decrypt start', encryptedBytes.length/*, bytesToHex(keyBytes), bytesToHex(ivBytes)*/);
|
|
||||||
|
|
||||||
|
// console.log(dT(), 'AES decrypt start', encryptedBytes.length);
|
||||||
var decryptedWords = CryptoJS.AES.decrypt({ciphertext: bytesToWords(encryptedBytes)}, bytesToWords(keyBytes), {
|
var decryptedWords = CryptoJS.AES.decrypt({ciphertext: bytesToWords(encryptedBytes)}, bytesToWords(keyBytes), {
|
||||||
iv: bytesToWords(ivBytes),
|
iv: bytesToWords(ivBytes),
|
||||||
padding: CryptoJS.pad.NoPadding,
|
padding: CryptoJS.pad.NoPadding,
|
||||||
@ -278,8 +301,7 @@ function aesDecrypt (encryptedBytes, keyBytes, ivBytes) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var bytes = bytesFromWords(decryptedWords);
|
var bytes = bytesFromWords(decryptedWords);
|
||||||
|
// console.log(dT(), 'AES decrypt finish');
|
||||||
// console.log('AES decrypt finish');
|
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,15 @@ onmessage = function (e) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'sha1-hash':
|
case 'sha1-hash':
|
||||||
result = sha1Hash(e.data.bytes);
|
result = sha1HashSync(e.data.bytes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'aes-encrypt':
|
case 'aes-encrypt':
|
||||||
result = aesEncrypt(e.data.bytes, e.data.keyBytes, e.data.ivBytes);
|
result = aesEncryptSync(e.data.bytes, e.data.keyBytes, e.data.ivBytes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'aes-decrypt':
|
case 'aes-decrypt':
|
||||||
result = aesDecrypt(e.data.encryptedBytes, e.data.keyBytes, e.data.ivBytes);
|
result = aesDecryptSync(e.data.encryptedBytes, e.data.keyBytes, e.data.ivBytes);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -82,7 +82,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
var buffer = RSAPublicKey.getBuffer();
|
var buffer = RSAPublicKey.getBuffer();
|
||||||
|
|
||||||
var fingerprintBytes = sha1Hash(buffer).slice(-8);
|
var fingerprintBytes = sha1BytesSync(buffer).slice(-8);
|
||||||
fingerprintBytes.reverse();
|
fingerprintBytes.reverse();
|
||||||
|
|
||||||
publicKeysParsed[bytesToHex(fingerprintBytes)] = {
|
publicKeysParsed[bytesToHex(fingerprintBytes)] = {
|
||||||
@ -169,7 +169,11 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
|
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
|
||||||
|
|
||||||
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/),
|
var chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/),
|
||||||
chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false;
|
chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false,
|
||||||
|
xhrSendBuffer = !('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30);
|
||||||
|
|
||||||
|
delete $http.defaults.headers.post['Content-Type'];
|
||||||
|
delete $http.defaults.headers.common['Accept'];
|
||||||
|
|
||||||
function mtpSendPlainRequest (dcID, requestBuffer) {
|
function mtpSendPlainRequest (dcID, requestBuffer) {
|
||||||
var requestLength = requestBuffer.byteLength,
|
var requestLength = requestBuffer.byteLength,
|
||||||
@ -190,16 +194,10 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
resultArray.set(headerArray);
|
resultArray.set(headerArray);
|
||||||
resultArray.set(requestArray, headerArray.length);
|
resultArray.set(requestArray, headerArray.length);
|
||||||
|
|
||||||
delete $http.defaults.headers.post['Content-Type'];
|
var requestData = xhrSendBuffer ? resultBuffer : resultArray,
|
||||||
delete $http.defaults.headers.common['Accept'];
|
requestPromise;
|
||||||
|
|
||||||
if (!('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30)) {
|
|
||||||
resultArray = resultArray.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestPromise;
|
|
||||||
try {
|
try {
|
||||||
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(dcID) + '/apiw1', resultArray, {
|
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(dcID) + '/apiw1', requestData, {
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
transformRequest: null
|
transformRequest: null
|
||||||
});
|
});
|
||||||
@ -305,7 +303,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
new_nonce: auth.newNonce
|
new_nonce: auth.newNonce
|
||||||
}, 'P_Q_inner_data', 'DECRYPTED_DATA');
|
}, 'P_Q_inner_data', 'DECRYPTED_DATA');
|
||||||
|
|
||||||
var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes());
|
var dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes());
|
||||||
|
|
||||||
var request = new TLSerialization({mtproto: true});
|
var request = new TLSerialization({mtproto: true});
|
||||||
request.storeMethod('req_DH_params', {
|
request.storeMethod('req_DH_params', {
|
||||||
@ -337,7 +335,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response._ == 'server_DH_params_fail') {
|
if (response._ == 'server_DH_params_fail') {
|
||||||
var newNonceHash = sha1Hash(auth.newNonce).slice(-16)
|
var newNonceHash = sha1BytesSync(auth.newNonce).slice(-16);
|
||||||
if (!bytesCmp (newNonceHash, response.new_nonce_hash)) {
|
if (!bytesCmp (newNonceHash, response.new_nonce_hash)) {
|
||||||
deferred.reject(new Error('server_DH_params_fail new_nonce_hash mismatch'));
|
deferred.reject(new Error('server_DH_params_fail new_nonce_hash mismatch'));
|
||||||
return false;
|
return false;
|
||||||
@ -362,10 +360,10 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
function mtpDecryptServerDhDataAnswer (auth, encryptedAnswer) {
|
function mtpDecryptServerDhDataAnswer (auth, encryptedAnswer) {
|
||||||
auth.localTime = tsNow();
|
auth.localTime = tsNow();
|
||||||
|
|
||||||
auth.tmpAesKey = sha1Hash(auth.newNonce.concat(auth.serverNonce)).concat(sha1Hash(auth.serverNonce.concat(auth.newNonce)).slice(0, 12));
|
auth.tmpAesKey = sha1BytesSync(auth.newNonce.concat(auth.serverNonce)).concat(sha1BytesSync(auth.serverNonce.concat(auth.newNonce)).slice(0, 12));
|
||||||
auth.tmpAesIv = sha1Hash(auth.serverNonce.concat(auth.newNonce)).slice(12).concat(sha1Hash([].concat(auth.newNonce, auth.newNonce)), auth.newNonce.slice(0, 4));
|
auth.tmpAesIv = sha1BytesSync(auth.serverNonce.concat(auth.newNonce)).slice(12).concat(sha1BytesSync([].concat(auth.newNonce, auth.newNonce)), auth.newNonce.slice(0, 4));
|
||||||
|
|
||||||
var answerWithHash = aesDecrypt(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv);
|
var answerWithHash = aesDecryptSync(encryptedAnswer, auth.tmpAesKey, auth.tmpAesIv);
|
||||||
|
|
||||||
var hash = answerWithHash.slice(0, 20);
|
var hash = answerWithHash.slice(0, 20);
|
||||||
var answerWithPadding = answerWithHash.slice(20);
|
var answerWithPadding = answerWithHash.slice(20);
|
||||||
@ -395,7 +393,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
var offset = deserializer.getOffset();
|
var offset = deserializer.getOffset();
|
||||||
|
|
||||||
if (!bytesCmp(hash, sha1Hash(answerWithPadding.slice(0, offset)))) {
|
if (!bytesCmp(hash, sha1BytesSync(answerWithPadding.slice(0, offset)))) {
|
||||||
throw new Error('server_DH_inner_data SHA1-hash mismatch');
|
throw new Error('server_DH_inner_data SHA1-hash mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,9 +418,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
g_b: gB,
|
g_b: gB,
|
||||||
}, 'Client_DH_Inner_Data');
|
}, 'Client_DH_Inner_Data');
|
||||||
|
|
||||||
var dataWithHash = sha1Hash(data.getBuffer()).concat(data.getBytes());
|
var dataWithHash = sha1BytesSync(data.getBuffer()).concat(data.getBytes());
|
||||||
|
|
||||||
var encryptedData = aesEncrypt(dataWithHash, auth.tmpAesKey, auth.tmpAesIv);
|
var encryptedData = aesEncryptSync(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', {
|
||||||
@ -451,14 +449,14 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
CryptoWorker.modPow(auth.gA, auth.b, auth.dhPrime).then(function (authKey) {
|
CryptoWorker.modPow(auth.gA, auth.b, auth.dhPrime).then(function (authKey) {
|
||||||
var authKeyHash = sha1Hash(authKey),
|
var authKeyHash = sha1BytesSync(authKey),
|
||||||
authKeyAux = authKeyHash.slice(0, 8),
|
authKeyAux = authKeyHash.slice(0, 8),
|
||||||
authKeyID = authKeyHash.slice(-8);
|
authKeyID = authKeyHash.slice(-8);
|
||||||
|
|
||||||
console.log(dT(), 'Got Set_client_DH_params_answer', response._);
|
console.log(dT(), 'Got Set_client_DH_params_answer', response._);
|
||||||
switch (response._) {
|
switch (response._) {
|
||||||
case 'dh_gen_ok':
|
case 'dh_gen_ok':
|
||||||
var newNonceHash1 = sha1Hash(auth.newNonce.concat([1], authKeyAux)).slice(-16);
|
var newNonceHash1 = sha1BytesSync(auth.newNonce.concat([1], authKeyAux)).slice(-16);
|
||||||
|
|
||||||
if (!bytesCmp(newNonceHash1, response.new_nonce_hash1)) {
|
if (!bytesCmp(newNonceHash1, response.new_nonce_hash1)) {
|
||||||
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash1 mismatch'));
|
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash1 mismatch'));
|
||||||
@ -476,7 +474,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'dh_gen_retry':
|
case 'dh_gen_retry':
|
||||||
var newNonceHash2 = sha1Hash(auth.newNonce.concat([2], authKeyAux)).slice(-16);
|
var newNonceHash2 = sha1BytesSync(auth.newNonce.concat([2], authKeyAux)).slice(-16);
|
||||||
if (!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
|
if (!bytesCmp(newNonceHash2, response.new_nonce_hash2)) {
|
||||||
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash2 mismatch'));
|
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash2 mismatch'));
|
||||||
return false;
|
return false;
|
||||||
@ -485,7 +483,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
return mtpSendSetClientDhParams(auth);
|
return mtpSendSetClientDhParams(auth);
|
||||||
|
|
||||||
case 'dh_gen_fail':
|
case 'dh_gen_fail':
|
||||||
var newNonceHash3 = sha1Hash(auth.newNonce.concat([3], authKeyAux)).slice(-16);
|
var newNonceHash3 = sha1BytesSync(auth.newNonce.concat([3], authKeyAux)).slice(-16);
|
||||||
if (!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
|
if (!bytesCmp(newNonceHash3, response.new_nonce_hash3)) {
|
||||||
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash3 mismatch'));
|
deferred.reject(new Error('Set_client_DH_params_answer new_nonce_hash3 mismatch'));
|
||||||
return false;
|
return false;
|
||||||
@ -553,7 +551,11 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
offline,
|
offline,
|
||||||
offlineInited = false,
|
offlineInited = false,
|
||||||
chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/),
|
chromeMatches = navigator.userAgent.match(/Chrome\/(\d+(\.\d+)?)/),
|
||||||
chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false;
|
chromeVersion = chromeMatches && parseFloat(chromeMatches[1]) || false,
|
||||||
|
xhrSendBuffer = !('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30);
|
||||||
|
|
||||||
|
delete $http.defaults.headers.post['Content-Type'];
|
||||||
|
delete $http.defaults.headers.common['Accept'];
|
||||||
|
|
||||||
$rootScope.retryOnline = function () {
|
$rootScope.retryOnline = function () {
|
||||||
$(document.body).trigger('online');
|
$(document.body).trigger('online');
|
||||||
@ -566,7 +568,9 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
this.iii = iii++;
|
this.iii = iii++;
|
||||||
|
|
||||||
this.authKey = authKey;
|
this.authKey = authKey;
|
||||||
this.authKeyID = sha1Hash(authKey).slice(-8);
|
this.authKeyUint8 = convertToUint8Array(authKey);
|
||||||
|
this.authKeyBuffer = convertToArrayBuffer(authKey);
|
||||||
|
this.authKeyID = sha1BytesSync(authKey).slice(-8);
|
||||||
|
|
||||||
this.serverSalt = serverSalt;
|
this.serverSalt = serverSalt;
|
||||||
|
|
||||||
@ -827,19 +831,47 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
};
|
};
|
||||||
|
|
||||||
MtpNetworker.prototype.getMsgKeyIv = function (msgKey, isOut) {
|
MtpNetworker.prototype.getMsgKeyIv = function (msgKey, isOut) {
|
||||||
var authKey = this.authKey,
|
var authKey = this.authKeyUint8,
|
||||||
x = isOut ? 0 : 8;
|
x = isOut ? 0 : 8,
|
||||||
|
sha1aText = new Uint8Array(48),
|
||||||
|
sha1bText = new Uint8Array(48),
|
||||||
|
sha1cText = new Uint8Array(48),
|
||||||
|
sha1dText = new Uint8Array(48),
|
||||||
|
promises = {};
|
||||||
|
|
||||||
var promises = {
|
sha1aText.set(msgKey, 0);
|
||||||
sha1a: CryptoWorker.sha1Hash(msgKey.concat(authKey.slice(x, x + 32))),
|
sha1aText.set(authKey.subarray(x, x + 32), 16);
|
||||||
sha1b: CryptoWorker.sha1Hash(authKey.slice(32 + x, 48 + x).concat(msgKey, authKey.slice(48 + x, 64 + x))),
|
promises.sha1a = CryptoWorker.sha1Hash(sha1aText);
|
||||||
sha1c: CryptoWorker.sha1Hash(authKey.slice(64 + x, 96 + x).concat(msgKey)),
|
|
||||||
sha1d: CryptoWorker.sha1Hash(msgKey.concat(authKey.slice(96 + x, 128 + x)))
|
sha1bText.set(authKey.subarray(x + 32, x + 48), 0);
|
||||||
};
|
sha1bText.set(msgKey, 16);
|
||||||
|
sha1bText.set(authKey.subarray(x + 48, x + 64), 32);
|
||||||
|
promises.sha1b = CryptoWorker.sha1Hash(sha1bText);
|
||||||
|
|
||||||
|
sha1cText.set(authKey.subarray(x + 64, x + 96), 0);
|
||||||
|
sha1cText.set(msgKey, 32);
|
||||||
|
promises.sha1c = CryptoWorker.sha1Hash(sha1cText);
|
||||||
|
|
||||||
|
sha1dText.set(msgKey, 0);
|
||||||
|
sha1dText.set(authKey.subarray(x + 96, x + 128), 16);
|
||||||
|
promises.sha1d = CryptoWorker.sha1Hash(sha1dText);
|
||||||
|
|
||||||
return $q.all(promises).then(function (result) {
|
return $q.all(promises).then(function (result) {
|
||||||
var aesKey = result.sha1a.slice(0, 8).concat(result.sha1b.slice(8, 20), result.sha1c.slice(4, 16));
|
var aesKey = new Uint8Array(32),
|
||||||
var aesIv = result.sha1a.slice(8, 20).concat(result.sha1b.slice(0, 8), result.sha1c.slice(16, 20), result.sha1d.slice(0, 8));
|
aesIv = new Uint8Array(32);
|
||||||
|
sha1a = new Uint8Array(result.sha1a),
|
||||||
|
sha1b = new Uint8Array(result.sha1b),
|
||||||
|
sha1c = new Uint8Array(result.sha1c),
|
||||||
|
sha1d = new Uint8Array(result.sha1d);
|
||||||
|
|
||||||
|
aesKey.set(sha1a.subarray(0, 8));
|
||||||
|
aesKey.set(sha1b.subarray(8, 20), 8);
|
||||||
|
aesKey.set(sha1c.subarray(4, 16), 20);
|
||||||
|
|
||||||
|
aesIv.set(sha1a.subarray(8, 20));
|
||||||
|
aesIv.set(sha1b.subarray(0, 8), 12);
|
||||||
|
aesIv.set(sha1c.subarray(16, 20), 20);
|
||||||
|
aesIv.set(sha1d.subarray(0, 8), 24);
|
||||||
|
|
||||||
return [aesKey, aesIv];
|
return [aesKey, aesIv];
|
||||||
});
|
});
|
||||||
@ -1076,14 +1108,14 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
MtpNetworker.prototype.getEncryptedMessage = function (bytes) {
|
MtpNetworker.prototype.getEncryptedMessage = function (bytes) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
console.log(dT(), 'Start encrypt', bytes.byteLength);
|
// console.log(dT(), 'Start encrypt', bytes.byteLength);
|
||||||
return CryptoWorker.sha1Hash(bytes).then(function (bytesHash) {
|
return CryptoWorker.sha1Hash(bytes).then(function (bytesHash) {
|
||||||
console.log(dT(), 'after hash');
|
// console.log(dT(), 'after hash');
|
||||||
var msgKey = bytesHash.slice(-16);
|
var msgKey = new Uint8Array(bytesHash).subarray(4, 20);
|
||||||
return self.getMsgKeyIv(msgKey, true).then(function (keyIv) {
|
return self.getMsgKeyIv(msgKey, true).then(function (keyIv) {
|
||||||
console.log(dT(), 'after msg key iv');
|
// console.log(dT(), 'after msg key iv');
|
||||||
return CryptoWorker.aesEncrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) {
|
return CryptoWorker.aesEncrypt(bytes, keyIv[0], keyIv[1]).then(function (encryptedBytes) {
|
||||||
console.log(dT(), 'Finish encrypt');
|
// console.log(dT(), 'Finish encrypt');
|
||||||
return {
|
return {
|
||||||
bytes: encryptedBytes,
|
bytes: encryptedBytes,
|
||||||
msgKey: msgKey
|
msgKey: msgKey
|
||||||
@ -1117,18 +1149,12 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
return this.getEncryptedMessage(data.getBuffer()).then(function (encryptedResult) {
|
return this.getEncryptedMessage(data.getBuffer()).then(function (encryptedResult) {
|
||||||
// console.log(dT(), 'Got encrypted out message'/*, encryptedResult*/);
|
// console.log(dT(), 'Got encrypted out message'/*, encryptedResult*/);
|
||||||
var request = new TLSerialization({startMaxLength: encryptedResult.bytes.length + 256});
|
var request = new TLSerialization({startMaxLength: encryptedResult.bytes.byteLength + 256});
|
||||||
request.storeIntBytes(self.authKeyID, 64, 'auth_key_id');
|
request.storeIntBytes(self.authKeyID, 64, 'auth_key_id');
|
||||||
request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key');
|
request.storeIntBytes(encryptedResult.msgKey, 128, 'msg_key');
|
||||||
request.storeRawBytes(encryptedResult.bytes, 'encrypted_data');
|
request.storeRawBytes(encryptedResult.bytes, 'encrypted_data');
|
||||||
|
|
||||||
delete $http.defaults.headers.post['Content-Type'];
|
var requestData = xhrSendBuffer ? request.getBuffer() : request.getArray();
|
||||||
delete $http.defaults.headers.common['Accept'];
|
|
||||||
|
|
||||||
var resultArray = request.getArray();
|
|
||||||
if (!('ArrayBufferView' in window) && (!chromeVersion || chromeVersion < 30)) {
|
|
||||||
resultArray = resultArray.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestPromise;
|
var requestPromise;
|
||||||
try {
|
try {
|
||||||
@ -1136,7 +1162,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
transformRequest: null
|
transformRequest: null
|
||||||
});
|
});
|
||||||
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(self.dcID) + '/apiw1', resultArray, options);
|
requestPromise = $http.post('http://' + MtpDcConfigurator.chooseServer(self.dcID) + '/apiw1', requestData, options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
requestPromise = $q.reject(e);
|
requestPromise = $q.reject(e);
|
||||||
}
|
}
|
||||||
@ -1172,32 +1198,29 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
var deserializer = new TLDeserialization(responseBuffer);
|
var deserializer = new TLDeserialization(responseBuffer);
|
||||||
|
|
||||||
var authKeyID = deserializer.fetchIntBytes(64, 'auth_key_id');
|
var authKeyID = deserializer.fetchIntBytes(64, false, 'auth_key_id');
|
||||||
if (!bytesCmp(authKeyID, this.authKeyID)) {
|
if (!bytesCmp(authKeyID, this.authKeyID)) {
|
||||||
throw new Error('Invalid server auth_key_id: ' + bytesToHex(authKeyID));
|
throw new Error('Invalid server auth_key_id: ' + bytesToHex(authKeyID));
|
||||||
}
|
}
|
||||||
var msgKey = deserializer.fetchIntBytes(128, 'msg_key');
|
var msgKey = deserializer.fetchIntBytes(128, true, 'msg_key'),
|
||||||
|
encryptedData = deserializer.fetchRawBytes(responseBuffer.byteLength - deserializer.getOffset(), true, 'encrypted_data');
|
||||||
var dataLength = responseBuffer.byteLength - deserializer.getOffset();
|
|
||||||
var encryptedData = deserializer.fetchRawBytes(dataLength, 'encrypted_data');
|
|
||||||
|
|
||||||
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
|
return this.getDecryptedMessage(msgKey, encryptedData).then(function (dataWithPadding) {
|
||||||
var buffer = bytesToArrayBuffer(dataWithPadding);
|
var deserializer = new TLDeserialization(dataWithPadding, {mtproto: true});
|
||||||
|
|
||||||
var deserializer = new TLDeserialization(buffer, {mtproto: true});
|
var salt = deserializer.fetchIntBytes(64, false, 'salt');
|
||||||
|
var sessionID = deserializer.fetchIntBytes(64, false, 'session_id');
|
||||||
var salt = deserializer.fetchIntBytes(64, 'salt');
|
|
||||||
var sessionID = deserializer.fetchIntBytes(64, 'session_id');
|
|
||||||
var messageID = deserializer.fetchLong('message_id');
|
var messageID = deserializer.fetchLong('message_id');
|
||||||
|
|
||||||
var seqNo = deserializer.fetchInt('seq_no');
|
var seqNo = deserializer.fetchInt('seq_no');
|
||||||
|
|
||||||
var messageBody = deserializer.fetchRawBytes(false, 'message_data');
|
var messageBody = deserializer.fetchRawBytes(false, true, 'message_data');
|
||||||
|
|
||||||
var offset = deserializer.getOffset();
|
var hashData = convertToUint8Array(dataWithPadding).subarray(0, deserializer.getOffset());
|
||||||
|
|
||||||
return CryptoWorker.sha1Hash(dataWithPadding.slice(0, offset)).then(function (dataHashed) {
|
return CryptoWorker.sha1Hash(hashData).then(function (dataHash) {
|
||||||
if (!bytesCmp(msgKey, dataHashed.slice(-16))) {
|
if (!bytesCmp(msgKey, bytesFromArrayBuffer(dataHash).slice(-16))) {
|
||||||
|
console.warn(msgKey, bytesFromArrayBuffer(dataHash));
|
||||||
throw new Error('server msgKey mismatch');
|
throw new Error('server msgKey mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,18 +500,16 @@ angular.module('izhukov.utils', [])
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (navigator.mimeTypes['application/x-pnacl'] !== undefined) {
|
if (navigator.mimeTypes['application/x-pnacl'] !== undefined) {
|
||||||
var listener = $('<div id="nacl_listener"><embed id="mtproto_crypto" width="0" height="0" src="nacl/mtproto_crypto.nmf" type="application/x-pnacl" /></div>').appendTo($('body'))[0];
|
var listener = $('<div id="nacl_listener"><embed id="mtproto_crypto" width="0" height="0" src="nacl/mtproto_crypto.nmf?'+Math.random()+'" type="application/x-pnacl" /></div>').appendTo($('body'))[0];
|
||||||
listener.addEventListener('load', function (e) {
|
listener.addEventListener('load', function (e) {
|
||||||
aesNaClEmbed = listener.firstChild;
|
aesNaClEmbed = listener.firstChild;
|
||||||
console.warn('NaCl ready', aesNaClEmbed);
|
console.log(dT(), 'NaCl ready');
|
||||||
}, true);
|
}, true);
|
||||||
listener.addEventListener('message', function (e) {
|
listener.addEventListener('message', function (e) {
|
||||||
console.log(e.data.result);
|
|
||||||
console.log(bytesFromArrayBuffer(e.data.result));
|
|
||||||
finalizeTask(e.data.taskID, e.data.result);
|
finalizeTask(e.data.taskID, e.data.result);
|
||||||
}, true);
|
}, true);
|
||||||
listener.addEventListener('error', function (e) {
|
listener.addEventListener('error', function (e) {
|
||||||
console.error(e);
|
console.error('NaCl error', e);
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,57 +541,49 @@ angular.module('izhukov.utils', [])
|
|||||||
return {
|
return {
|
||||||
sha1Hash: function (bytes) {
|
sha1Hash: function (bytes) {
|
||||||
if (useSha1Crypto) {
|
if (useSha1Crypto) {
|
||||||
|
// We don't use buffer since typedArray.subarray(...).buffer gives the whole buffer and not sliced one. webCrypto.digest supports typed array
|
||||||
var deferred = $q.defer(),
|
var deferred = $q.defer(),
|
||||||
buffer = bytes instanceof ArrayBuffer
|
bytesTyped = Array.isArray(bytes) ? convertToUint8Array(bytes) : bytes;
|
||||||
? bytes
|
// console.log(dT(), 'Native sha1 start');
|
||||||
: bytesToArrayBuffer(bytes);
|
webCrypto.digest({name: 'SHA-1'}, bytesTyped).then(function (digest) {
|
||||||
|
// console.log(dT(), 'Native sha1 done');
|
||||||
webCrypto.digest({name: 'SHA-1'}, buffer).then(function (digest) {
|
deferred.resolve(digest);
|
||||||
deferred.resolve(bytesFromArrayBuffer(digest));
|
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
console.error('Crypto digest error', e);
|
console.error('Crypto digest error', e);
|
||||||
useSha1Crypto = false;
|
useSha1Crypto = false;
|
||||||
deferred.resolve(sha1Hash(bytes));
|
deferred.resolve(sha1HashSync(bytes));
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
if (worker && false) { // due overhead for data transfer
|
|
||||||
return performTaskWorker ('sha1-hash', {bytes: bytes});
|
|
||||||
}
|
|
||||||
return $timeout(function () {
|
return $timeout(function () {
|
||||||
return sha1Hash(bytes);
|
return sha1HashSync(bytes);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
aesEncrypt: function (bytes, keyBytes, ivBytes) {
|
aesEncrypt: function (bytes, keyBytes, ivBytes) {
|
||||||
if (aesNaClEmbed) {
|
if (aesNaClEmbed) {
|
||||||
|
// aesEncryptSync(bytes, keyBytes, ivBytes);
|
||||||
return performTaskWorker('aes-encrypt', {
|
return performTaskWorker('aes-encrypt', {
|
||||||
bytes: bytes,
|
bytes: addPadding(convertToArrayBuffer(bytes)),
|
||||||
keyBytes: bytesToArrayBuffer(keyBytes),
|
keyBytes: convertToArrayBuffer(keyBytes),
|
||||||
ivBytes: bytesToArrayBuffer(ivBytes)
|
ivBytes: convertToArrayBuffer(ivBytes)
|
||||||
}, aesNaClEmbed);
|
|
||||||
}
|
|
||||||
if (worker && false) { // due overhead for data transfer
|
|
||||||
return performTaskWorker('aes-encrypt', {
|
|
||||||
bytes: bytes,
|
|
||||||
keyBytes: keyBytes,
|
|
||||||
ivBytes: ivBytes
|
|
||||||
}, aesNaClEmbed);
|
}, aesNaClEmbed);
|
||||||
}
|
}
|
||||||
return $timeout(function () {
|
return $timeout(function () {
|
||||||
return aesEncrypt(bytes, keyBytes, ivBytes);
|
return convertToArrayBuffer(aesEncryptSync(bytes, keyBytes, ivBytes));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) {
|
aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) {
|
||||||
if (worker && false) { // due overhead for data transfer
|
if (aesNaClEmbed) {
|
||||||
|
// aesDecryptSync(encryptedBytes, keyBytes, ivBytes);
|
||||||
return performTaskWorker('aes-decrypt', {
|
return performTaskWorker('aes-decrypt', {
|
||||||
encryptedBytes: encryptedBytes,
|
encryptedBytes: addPadding(convertToArrayBuffer(encryptedBytes)),
|
||||||
keyBytes: keyBytes,
|
keyBytes: convertToArrayBuffer(keyBytes),
|
||||||
ivBytes: ivBytes
|
ivBytes: convertToArrayBuffer(ivBytes)
|
||||||
});
|
}, aesNaClEmbed);
|
||||||
}
|
}
|
||||||
return $timeout(function () {
|
return $timeout(function () {
|
||||||
return aesDecrypt(encryptedBytes, keyBytes, ivBytes);
|
return convertToArrayBuffer(aesDecryptSync(encryptedBytes, keyBytes, ivBytes));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
factorize: function (bytes) {
|
factorize: function (bytes) {
|
||||||
|
@ -170,6 +170,9 @@ TLSerialization.prototype.storeBytes = function (bytes, field) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TLSerialization.prototype.storeIntBytes = function (bytes, bits, field) {
|
TLSerialization.prototype.storeIntBytes = function (bytes, bits, field) {
|
||||||
|
if (bytes instanceof ArrayBuffer) {
|
||||||
|
bytes = new Uint8Array(bytes);
|
||||||
|
}
|
||||||
var len = bytes.length;
|
var len = bytes.length;
|
||||||
if ((bits % 32) || (len * 8) != bits) {
|
if ((bits % 32) || (len * 8) != bits) {
|
||||||
throw new Error('Invalid bits: ' + bits + ', ' + bytes.length);
|
throw new Error('Invalid bits: ' + bits + ', ' + bytes.length);
|
||||||
@ -178,13 +181,15 @@ TLSerialization.prototype.storeIntBytes = function (bytes, bits, field) {
|
|||||||
this.debug && console.log('>>>', bytesToHex(bytes), (field || '') + ':int' + bits);
|
this.debug && console.log('>>>', bytesToHex(bytes), (field || '') + ':int' + bits);
|
||||||
this.checkLength(len);
|
this.checkLength(len);
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
this.byteView.set(bytes, this.offset);
|
||||||
this.byteView[this.offset++] = bytes[i];
|
this.offset += len;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TLSerialization.prototype.storeRawBytes = function (bytes, field) {
|
TLSerialization.prototype.storeRawBytes = function (bytes, field) {
|
||||||
var len = bytes.byteLength || bytes.length;
|
if (bytes instanceof ArrayBuffer) {
|
||||||
|
bytes = new Uint8Array(bytes);
|
||||||
|
}
|
||||||
|
var len = bytes.length;
|
||||||
|
|
||||||
this.debug && console.log('>>>', bytesToHex(bytes), (field || ''));
|
this.debug && console.log('>>>', bytesToHex(bytes), (field || ''));
|
||||||
this.checkLength(len);
|
this.checkLength(len);
|
||||||
@ -412,12 +417,18 @@ TLDeserialization.prototype.fetchBytes = function (field) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
TLDeserialization.prototype.fetchIntBytes = function (bits, field) {
|
TLDeserialization.prototype.fetchIntBytes = function (bits, typed, field) {
|
||||||
if (bits % 32) {
|
if (bits % 32) {
|
||||||
throw new Error('Invalid bits: ' + bits);
|
throw new Error('Invalid bits: ' + bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
var len = bits / 8;
|
var len = bits / 8;
|
||||||
|
if (typed) {
|
||||||
|
var result = this.byteView.subarray(this.offset, this.offset + len);
|
||||||
|
this.offset += len;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
var bytes = [];
|
var bytes = [];
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
bytes.push(this.byteView[this.offset++]);
|
bytes.push(this.byteView[this.offset++]);
|
||||||
@ -429,11 +440,18 @@ TLDeserialization.prototype.fetchIntBytes = function (bits, field) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TLDeserialization.prototype.fetchRawBytes = function (len, field) {
|
TLDeserialization.prototype.fetchRawBytes = function (len, typed, field) {
|
||||||
if (len === false) {
|
if (len === false) {
|
||||||
len = this.readInt((field || '') + '_length');
|
len = this.readInt((field || '') + '_length');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typed) {
|
||||||
|
var bytes = new Uint8Array(len);
|
||||||
|
bytes.set(this.byteView.subarray(this.offset, this.offset + len));
|
||||||
|
this.offset += len;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
var bytes = [];
|
var bytes = [];
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
bytes.push(this.byteView[this.offset++]);
|
bytes.push(this.byteView[this.offset++]);
|
||||||
@ -448,9 +466,9 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case 'int': return this.fetchInt(field);
|
case 'int': return this.fetchInt(field);
|
||||||
case 'long': return this.fetchLong(field);
|
case 'long': return this.fetchLong(field);
|
||||||
case 'int128': return this.fetchIntBytes(128, field);
|
case 'int128': return this.fetchIntBytes(128, false, field);
|
||||||
case 'int256': return this.fetchIntBytes(256, field);
|
case 'int256': return this.fetchIntBytes(256, false, field);
|
||||||
case 'int512': return this.fetchIntBytes(512, field);
|
case 'int512': return this.fetchIntBytes(512, false, field);
|
||||||
case 'string': return this.fetchString(field);
|
case 'string': return this.fetchString(field);
|
||||||
case 'bytes': return this.fetchBytes(field);
|
case 'bytes': return this.fetchBytes(field);
|
||||||
case 'double': return this.fetchDouble(field);
|
case 'double': return this.fetchDouble(field);
|
||||||
|
@ -48,16 +48,7 @@ clean:
|
|||||||
|
|
||||||
mtproto_crypto.bc: mtproto_crypto.cc aes_core.c aes_ige.c aes_misc.c
|
mtproto_crypto.bc: mtproto_crypto.cc aes_core.c aes_ige.c aes_misc.c
|
||||||
$(PNACL_CXX) -o $@ $^ -O2 $(CXXFLAGS) $(LDFLAGS)
|
$(PNACL_CXX) -o $@ $^ -O2 $(CXXFLAGS) $(LDFLAGS)
|
||||||
|
# $(PNACL_CXX) -g -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
|
||||||
|
|
||||||
mtproto_crypto.pexe: mtproto_crypto.bc
|
mtproto_crypto.pexe: mtproto_crypto.bc
|
||||||
$(PNACL_FINALIZE) -o $@ $<
|
$(PNACL_FINALIZE) -o $@ $<
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Makefile target to run the SDK's simple HTTP server and serve this example.
|
|
||||||
#
|
|
||||||
HTTPD_PY := python $(NACL_SDK_ROOT)/tools/httpd.py
|
|
||||||
|
|
||||||
.PHONY: serve
|
|
||||||
serve: all
|
|
||||||
$(HTTPD_PY) -C $(CURDIR)
|
|
||||||
|
Binary file not shown.
@ -61,11 +61,6 @@ class MtprotoCryptoInstance : public pp::Instance {
|
|||||||
/// @param[in] var_message The message posted by the browser.
|
/// @param[in] var_message The message posted by the browser.
|
||||||
virtual void HandleMessage(const pp::Var& var_message) {
|
virtual void HandleMessage(const pp::Var& var_message) {
|
||||||
|
|
||||||
// if (1) {
|
|
||||||
// PostMessage(var_message);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!var_message.is_dictionary()) {
|
if (!var_message.is_dictionary()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -80,7 +75,7 @@ class MtprotoCryptoInstance : public pp::Instance {
|
|||||||
|
|
||||||
int32_t intTaskID = varTaskID.AsInt();
|
int32_t intTaskID = varTaskID.AsInt();
|
||||||
std::string strTask = varTask.AsString();
|
std::string strTask = varTask.AsString();
|
||||||
pp::Var varResult;// = pp::Var::Var();
|
pp::Var varResult;
|
||||||
|
|
||||||
if (strTask == "aes-encrypt") {
|
if (strTask == "aes-encrypt") {
|
||||||
pp::Var varData = request.Get(pp::Var::Var("bytes"));
|
pp::Var varData = request.Get(pp::Var::Var("bytes"));
|
||||||
@ -95,21 +90,42 @@ class MtprotoCryptoInstance : public pp::Instance {
|
|||||||
pp::VarArrayBuffer abKey = pp::VarArrayBuffer::VarArrayBuffer(varKey);
|
pp::VarArrayBuffer abKey = pp::VarArrayBuffer::VarArrayBuffer(varKey);
|
||||||
pp::VarArrayBuffer abIv = pp::VarArrayBuffer::VarArrayBuffer(varIv);
|
pp::VarArrayBuffer abIv = pp::VarArrayBuffer::VarArrayBuffer(varIv);
|
||||||
|
|
||||||
int length = abData.ByteLength();
|
|
||||||
char* what = static_cast<char*>(abData.Map());
|
char* what = static_cast<char*>(abData.Map());
|
||||||
char* keyBuff = static_cast<char*>(abKey.Map());
|
char* keyBuff = static_cast<char*>(abKey.Map());
|
||||||
char* ivBuff = static_cast<char*>(abIv.Map());
|
char* ivBuff = static_cast<char*>(abIv.Map());
|
||||||
|
int length = abData.ByteLength();
|
||||||
|
|
||||||
AES_KEY akey;
|
AES_KEY akey;
|
||||||
AES_set_encrypt_key((const unsigned char *) keyBuff, 32 * 8, &akey);
|
AES_set_encrypt_key((const unsigned char *) keyBuff, 32 * 8, &akey);
|
||||||
|
AES_ige_encrypt((const unsigned char *)what, (unsigned char *)what, length, &akey, (unsigned char *)ivBuff, AES_ENCRYPT);
|
||||||
|
|
||||||
|
varResult = abData;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (strTask == "aes-decrypt") {
|
||||||
|
pp::Var varData = request.Get(pp::Var::Var("encryptedBytes"));
|
||||||
|
pp::Var varKey = request.Get(pp::Var::Var("keyBytes"));
|
||||||
|
pp::Var varIv = request.Get(pp::Var::Var("ivBytes"));
|
||||||
|
|
||||||
|
if (!varData.is_array_buffer() || !varKey.is_array_buffer() || !varIv.is_array_buffer()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::VarArrayBuffer abData = pp::VarArrayBuffer::VarArrayBuffer(varData);
|
||||||
|
pp::VarArrayBuffer abKey = pp::VarArrayBuffer::VarArrayBuffer(varKey);
|
||||||
|
pp::VarArrayBuffer abIv = pp::VarArrayBuffer::VarArrayBuffer(varIv);
|
||||||
|
|
||||||
|
char* what = static_cast<char*>(abData.Map());
|
||||||
|
char* keyBuff = static_cast<char*>(abKey.Map());
|
||||||
|
char* ivBuff = static_cast<char*>(abIv.Map());
|
||||||
|
int length = abData.ByteLength();
|
||||||
|
|
||||||
|
AES_KEY akey;
|
||||||
|
AES_set_decrypt_key((const unsigned char *) keyBuff, 32 * 8, &akey);
|
||||||
AES_ige_encrypt((const unsigned char *)what, (unsigned char *)what, length, &akey, (unsigned char *)ivBuff, AES_DECRYPT);
|
AES_ige_encrypt((const unsigned char *)what, (unsigned char *)what, length, &akey, (unsigned char *)ivBuff, AES_DECRYPT);
|
||||||
|
|
||||||
// varResult = pp::Var::Var(what);
|
|
||||||
// varResult = pp::VarArrayBuffer::VarArrayBuffer(pp::Var::Var(what));
|
|
||||||
abData.Unmap();
|
|
||||||
varResult = abData;
|
varResult = abData;
|
||||||
// varResult = pp::VarArrayBuffer::VarArrayBuffer();
|
|
||||||
// pp::VarArrayBuffer varResult(what);
|
|
||||||
} else {
|
} else {
|
||||||
varResult = pp::Var::Var();
|
varResult = pp::Var::Var();
|
||||||
}
|
}
|
||||||
@ -119,13 +135,6 @@ class MtprotoCryptoInstance : public pp::Instance {
|
|||||||
response.Set(pp::Var::Var("result"), varResult);
|
response.Set(pp::Var::Var("result"), varResult);
|
||||||
|
|
||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
|
|
||||||
// std::string message = var_message.AsString();
|
|
||||||
// pp::Var var_reply;
|
|
||||||
// if (message == kHelloString) {
|
|
||||||
// var_reply = pp::Var(kReplyString);
|
|
||||||
// PostMessage(var_reply);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
"program": {
|
"program": {
|
||||||
"portable": {
|
"portable": {
|
||||||
"pnacl-translate": {
|
"pnacl-translate": {
|
||||||
"url": "mtproto_crypto.pexe?13"
|
"url": "mtproto_crypto.pexe?55",
|
||||||
|
"optlevel": 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
@ -89,7 +89,8 @@ StaticServlet.MimeMap = {
|
|||||||
'svg': 'image/svg+xml',
|
'svg': 'image/svg+xml',
|
||||||
'wav': 'audio/wav',
|
'wav': 'audio/wav',
|
||||||
'ico': 'image/vnd.microsoft.icon',
|
'ico': 'image/vnd.microsoft.icon',
|
||||||
'pexe': 'application/x-pnacl'
|
'pexe': 'application/x-pnacl',
|
||||||
|
'bc': 'application/x-pnacl'
|
||||||
};
|
};
|
||||||
|
|
||||||
StaticServlet.prototype.handleRequest = function(req, res) {
|
StaticServlet.prototype.handleRequest = function(req, res) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user