WebRTC audio/video call and conferencing server.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2388 lines
122 KiB

/**
* Copyright (C) 2015 Joe Bandenburg
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
define([
'protobufjs',
'traceur-runtime',
'axolotl-crypto'
], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('protobufjs'), require('traceur/bin/traceur-runtime'), require('axolotl-crypto'));
} else {
this.axolotl = factory(dcodeIO.ProtoBuf, 1, axolotlCrypto);
}
}(function (__external_1, __external_2, __external_axolotlCrypto) {
var global = this, define;
function _require(id) {
var module = _require.cache[id];
if (!module) {
var exports = {};
module = _require.cache[id] = {
id: id,
exports: exports
};
_require.modules[id].call(exports, module, exports);
}
return module.exports;
}
_require.cache = [];
_require.modules = [
function (module, exports) {
'use strict';
var $__src_47_Axolotl__, $__axolotl_45_crypto__;
var Axolotl = ($__src_47_Axolotl__ = _require(2), $__src_47_Axolotl__ && $__src_47_Axolotl__.__esModule && $__src_47_Axolotl__ || { default: $__src_47_Axolotl__ }).default;
var axolotlCrypto = ($__axolotl_45_crypto__ = _require(17), $__axolotl_45_crypto__ && $__axolotl_45_crypto__.__esModule && $__axolotl_45_crypto__ || { default: $__axolotl_45_crypto__ }).default;
module.exports = function (store) {
return new Axolotl(axolotlCrypto, store);
};
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__default = {
areEqual: function (left, right) {
if (left.byteLength !== right.byteLength) {
return false;
}
var leftView = new Uint8Array(left);
var rightView = new Uint8Array(right);
for (var i = 0; i < left.byteLength; i++) {
if (leftView[i] !== rightView[i]) {
return false;
}
}
return true;
},
concat: function () {
for (var buffers = [], $__0 = 0; $__0 < arguments.length; $__0++)
buffers[$__0] = arguments[$__0];
buffers = buffers.length === 1 ? buffers[0] : buffers;
var i;
var byteLength = 0;
for (i = 0; i < buffers.length; i++) {
byteLength += buffers[i].byteLength;
}
var newBuffer = new ArrayBuffer(byteLength);
var view = new Uint8Array(newBuffer);
var offset = 0;
for (i = 0; i < buffers.length; i++) {
view.set(new Uint8Array(buffers[i]), offset);
offset += buffers[i].byteLength;
}
return newBuffer;
},
fromByte: function (byte) {
return new Uint8Array([byte]).buffer;
},
stringify: function (buffer) {
var string = '';
var view = new Uint8Array(buffer);
for (var i = 0; i < buffer.byteLength; i++) {
var byte = view[i].toString(16);
if (byte.length === 1) {
string += '0';
}
string += byte;
}
return string;
},
parse: function (string) {
var buffer = new ArrayBuffer(string.length / 2);
var view = new Uint8Array(buffer);
for (var i = 0; i < string.length; i += 2) {
view[i / 2] = parseInt(string[i], 16) * 16 + parseInt(string[i + 1], 16);
}
return buffer;
}
};
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__SessionFactory__, $__SessionCipher__, $__Exceptions__, $__Store__, $__Crypto__, $__co__, $__axolotl_45_crypto__;
var SessionFactory = ($__SessionFactory__ = _require(13), $__SessionFactory__ && $__SessionFactory__.__esModule && $__SessionFactory__ || { default: $__SessionFactory__ }).default;
var SessionCipher = ($__SessionCipher__ = _require(12), $__SessionCipher__ && $__SessionCipher__.__esModule && $__SessionCipher__ || { default: $__SessionCipher__ }).default;
var InvalidMessageException = ($__Exceptions__ = _require(5), $__Exceptions__ && $__Exceptions__.__esModule && $__Exceptions__ || { default: $__Exceptions__ }).InvalidMessageException;
var Store = ($__Store__ = _require(15), $__Store__ && $__Store__.__esModule && $__Store__ || { default: $__Store__ }).default;
var Crypto = ($__Crypto__ = _require(4), $__Crypto__ && $__Crypto__.__esModule && $__Crypto__ || { default: $__Crypto__ }).default;
var co = ($__co__ = _require(18), $__co__ && $__co__.__esModule && $__co__ || { default: $__co__ }).default;
var axolotlCrypto = ($__axolotl_45_crypto__ = _require(17), $__axolotl_45_crypto__ && $__axolotl_45_crypto__.__esModule && $__axolotl_45_crypto__ || { default: $__axolotl_45_crypto__ }).default;
function Axolotl(crypto, store) {
var self = this;
var wrappedStore = new Store(store);
var wrappedCrypto = new Crypto(crypto);
var sessionFactory = new SessionFactory(wrappedCrypto, wrappedStore);
var sessionCipher = new SessionCipher(wrappedCrypto);
this.generateIdentityKeyPair = function () {
return wrappedCrypto.generateKeyPair();
};
this.generateRegistrationId = co.wrap($traceurRuntime.initGeneratorFunction(function $__9(extendedRange) {
var upperLimit, bytes, number;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
upperLimit = extendedRange ? 2147483646 : 16380;
$ctx.state = 8;
break;
case 8:
$ctx.state = 2;
return wrappedCrypto.randomBytes(4);
case 2:
bytes = $ctx.sent;
$ctx.state = 4;
break;
case 4:
number = new Uint32Array(bytes)[0];
$ctx.state = 10;
break;
case 10:
$ctx.returnValue = number % upperLimit + 1;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__9, this);
}));
this.generatePreKeys = co.wrap($traceurRuntime.initGeneratorFunction(function $__10(start, count) {
var results, i, $__11, $__12, $__13, $__14, $__15, $__16;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
results = [];
start--;
$ctx.state = 15;
break;
case 15:
i = 0;
$ctx.state = 11;
break;
case 11:
$ctx.state = i < count ? 5 : 9;
break;
case 8:
i++;
$ctx.state = 11;
break;
case 5:
$__11 = results.push;
$__12 = wrappedCrypto.generateKeyPair;
$__13 = $__12.call(wrappedCrypto);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__13;
case 2:
$__14 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__15 = {
id: (start + i) % 16777214 + 1,
keyPair: $__14
};
$__16 = $__11.call(results, $__15);
$ctx.state = 8;
break;
case 9:
$ctx.returnValue = results;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__10, this);
}));
this.generateLastResortPreKey = co.wrap($traceurRuntime.initGeneratorFunction(function $__17() {
var $__18, $__19, $__20, $__21;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__18 = wrappedCrypto.generateKeyPair;
$__19 = $__18.call(wrappedCrypto);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__19;
case 2:
$__20 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__21 = {
id: 16777215,
keyPair: $__20
};
$ctx.state = 8;
break;
case 8:
$ctx.returnValue = $__21;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__17, this);
}));
this.generateSignedPreKey = co.wrap($traceurRuntime.initGeneratorFunction(function $__22(identityKeyPair, signedPreKeyId) {
var keyPair, signature;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return wrappedCrypto.generateKeyPair();
case 2:
keyPair = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return wrappedCrypto.sign(identityKeyPair.private, keyPair.public);
case 6:
signature = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$ctx.returnValue = {
id: signedPreKeyId,
keyPair: keyPair,
signature: signature
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__22, this);
}));
this.createSessionFromPreKeyBundle = sessionFactory.createSessionFromPreKeyBundle;
this.encryptMessage = sessionCipher.encryptMessage;
this.decryptWhisperMessage = sessionCipher.decryptWhisperMessage;
this.decryptPreKeyWhisperMessage = co.wrap($traceurRuntime.initGeneratorFunction(function $__23(session, preKeyWhisperMessageBytes) {
var $__7, newSession, identityKey, registrationId, $__8, finalSession, message, $__24, $__25, $__26, $__27, $__28, $__29, $__30, $__31, $__32, $__33, $__34;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__24 = sessionFactory.createSessionFromPreKeyWhisperMessage;
$__25 = $__24.call(sessionFactory, session, preKeyWhisperMessageBytes);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__25;
case 2:
$__26 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__7 = $__26;
$__27 = $__7.session;
newSession = $__27;
$__28 = $__7.identityKey;
identityKey = $__28;
$__29 = $__7.registrationId;
registrationId = $__29;
$ctx.state = 8;
break;
case 8:
$__30 = sessionCipher.decryptPreKeyWhisperMessage;
$__31 = $__30.call(sessionCipher, newSession, preKeyWhisperMessageBytes);
$ctx.state = 14;
break;
case 14:
$ctx.state = 10;
return $__31;
case 10:
$__32 = $ctx.sent;
$ctx.state = 12;
break;
case 12:
$__8 = $__32;
$__33 = $__8.session;
finalSession = $__33;
$__34 = $__8.message;
message = $__34;
$ctx.state = 16;
break;
case 16:
$ctx.returnValue = {
message: message,
session: finalSession,
identityKey: identityKey,
registrationId: registrationId
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__23, this);
}));
Object.freeze(self);
}
var $__default = Axolotl;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var Chain = function Chain(key) {
this.key = key;
this.index = 0;
this.messageKeys = [];
Object.seal(this);
};
$traceurRuntime.createClass(Chain, {}, {});
var $__default = Chain;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__PromiseInterfaceDecorator__;
var PromiseInterfaceDecorator = ($__PromiseInterfaceDecorator__ = _require(8), $__PromiseInterfaceDecorator__ && $__PromiseInterfaceDecorator__.__esModule && $__PromiseInterfaceDecorator__ || { default: $__PromiseInterfaceDecorator__ }).default;
var methodNames = [
'generateKeyPair',
'calculateAgreement',
'randomBytes',
'sign',
'verifySignature',
'hmac',
'encrypt',
'decrypt'
];
var Crypto = function Crypto(crypto) {
$traceurRuntime.superConstructor($Crypto).call(this, crypto, methodNames);
};
var $Crypto = Crypto;
$traceurRuntime.createClass(Crypto, {}, {}, PromiseInterfaceDecorator);
var $__default = Crypto;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
InvalidMessageException: {
get: function () {
return InvalidMessageException;
}
},
DuplicateMessageException: {
get: function () {
return DuplicateMessageException;
}
},
InvalidKeyException: {
get: function () {
return InvalidKeyException;
}
},
UnsupportedProtocolVersionException: {
get: function () {
return UnsupportedProtocolVersionException;
}
},
UntrustedIdentityException: {
get: function () {
return UntrustedIdentityException;
}
},
__esModule: { value: true }
});
var InvalidMessageException = function InvalidMessageException() {
$traceurRuntime.superConstructor($InvalidMessageException).apply(this, arguments);
};
var $InvalidMessageException = InvalidMessageException;
$traceurRuntime.createClass(InvalidMessageException, {}, {}, Error);
var DuplicateMessageException = function DuplicateMessageException() {
$traceurRuntime.superConstructor($DuplicateMessageException).apply(this, arguments);
};
var $DuplicateMessageException = DuplicateMessageException;
$traceurRuntime.createClass(DuplicateMessageException, {}, {}, Error);
var InvalidKeyException = function InvalidKeyException() {
$traceurRuntime.superConstructor($InvalidKeyException).apply(this, arguments);
};
var $InvalidKeyException = InvalidKeyException;
$traceurRuntime.createClass(InvalidKeyException, {}, {}, Error);
var UnsupportedProtocolVersionException = function UnsupportedProtocolVersionException() {
$traceurRuntime.superConstructor($UnsupportedProtocolVersionException).apply(this, arguments);
};
var $UnsupportedProtocolVersionException = UnsupportedProtocolVersionException;
$traceurRuntime.createClass(UnsupportedProtocolVersionException, {}, {}, Error);
var UntrustedIdentityException = function UntrustedIdentityException() {
$traceurRuntime.superConstructor($UntrustedIdentityException).apply(this, arguments);
};
var $UntrustedIdentityException = UntrustedIdentityException;
$traceurRuntime.createClass(UntrustedIdentityException, {}, {}, Error);
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__ArrayBufferUtils__, $__co__;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var co = ($__co__ = _require(18), $__co__ && $__co__.__esModule && $__co__ || { default: $__co__ }).default;
var hashOutputSize = 32;
var iterationStartOffset = 1;
function HKDF(crypto) {
var self = this;
var extract = function (salt, inputKeyMaterial) {
return crypto.hmac(salt, inputKeyMaterial);
};
var expand = co.wrap($traceurRuntime.initGeneratorFunction(function $__2(prk, info, outputByteCount) {
var iterations, mixin, result, remainingBytes, i, inputBytes, stepResultArray, stepResult, stepSize, stepSlice;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
iterations = Math.ceil(outputByteCount / hashOutputSize);
mixin = new ArrayBuffer(0);
result = new Uint8Array(outputByteCount);
remainingBytes = outputByteCount;
$ctx.state = 15;
break;
case 15:
i = iterationStartOffset;
$ctx.state = 11;
break;
case 11:
$ctx.state = i < iterations + iterationStartOffset ? 5 : 9;
break;
case 8:
i++;
$ctx.state = 11;
break;
case 5:
inputBytes = ArrayBufferUtils.concat(mixin, info, new Uint8Array([i]).buffer);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return crypto.hmac(prk, inputBytes);
case 2:
stepResultArray = $ctx.sent;
$ctx.state = 4;
break;
case 4:
stepResult = new Uint8Array(stepResultArray);
stepSize = Math.min(remainingBytes, stepResult.length);
stepSlice = stepResult.subarray(0, stepSize);
result.set(stepSlice, outputByteCount - remainingBytes);
mixin = stepResultArray;
remainingBytes -= stepSize;
$ctx.state = 8;
break;
case 9:
$ctx.returnValue = result.buffer;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__2, this);
}));
self.deriveSecretsWithSalt = co.wrap($traceurRuntime.initGeneratorFunction(function $__3(inputKeyMaterial, salt, info, outputByteCount) {
var prk, $__4, $__5;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return extract(salt, inputKeyMaterial);
case 2:
prk = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__4 = expand(prk, info, outputByteCount);
$ctx.state = 10;
break;
case 10:
$ctx.state = 6;
return $__4;
case 6:
$__5 = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$ctx.returnValue = $__5;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__3, this);
}));
self.deriveSecrets = function (inputKeyMaterial, info, outputByteCount) {
return self.deriveSecretsWithSalt(inputKeyMaterial, new ArrayBuffer(hashOutputSize), info, outputByteCount);
};
Object.freeze(self);
}
var $__default = HKDF;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__WhisperProtos__, $__ProtocolConstants__, $__ArrayBufferUtils__;
var WhisperProtos = ($__WhisperProtos__ = _require(16), $__WhisperProtos__ && $__WhisperProtos__.__esModule && $__WhisperProtos__ || { default: $__WhisperProtos__ }).default;
var ProtocolConstants = ($__ProtocolConstants__ = _require(9), $__ProtocolConstants__ && $__ProtocolConstants__.__esModule && $__ProtocolConstants__ || { default: $__ProtocolConstants__ }).default;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var getVersionField = function (version) {
return ArrayBufferUtils.fromByte((version.current << 4 | version.max) & 255);
};
var extractMessageVersion = function (versionByte) {
var view = new Uint8Array(versionByte);
return {
current: view[0] >> 4 & 15,
max: view[0] & 15
};
};
var toArrayBuffer = function (obj, key) {
if (obj[key]) {
obj[key] = obj[key].toArrayBuffer();
}
};
var encodeWhisperMessageMacInput = function (whisperMessage) {
var versionByte = getVersionField(whisperMessage.version);
var messageBytes = new WhisperProtos.WhisperMessage(whisperMessage.message).encode().toArrayBuffer();
return ArrayBufferUtils.concat(versionByte, messageBytes);
};
var $__default = {
decodeWhisperMessage: function (whisperMessageBytes) {
var messageBytes = whisperMessageBytes.slice(1, -ProtocolConstants.macByteCount);
var message = WhisperProtos.WhisperMessage.decode(messageBytes);
toArrayBuffer(message, 'ratchetKey');
toArrayBuffer(message, 'ciphertext');
return {
version: extractMessageVersion(whisperMessageBytes.slice(0, 1)),
message: message,
mac: whisperMessageBytes.slice(-ProtocolConstants.macByteCount)
};
},
decodeWhisperMessageMacInput: function (whisperMessageBytes) {
return whisperMessageBytes.slice(0, -ProtocolConstants.macByteCount);
},
encodeWhisperMessage: function (whisperMessage) {
return ArrayBufferUtils.concat(encodeWhisperMessageMacInput(whisperMessage), whisperMessage.mac);
},
encodeWhisperMessageMacInput: encodeWhisperMessageMacInput,
decodePreKeyWhisperMessage: function (preKeyWhisperMessageBytes) {
var message = WhisperProtos.PreKeyWhisperMessage.decode(preKeyWhisperMessageBytes.slice(1));
toArrayBuffer(message, 'message');
toArrayBuffer(message, 'baseKey');
toArrayBuffer(message, 'identityKey');
return {
version: extractMessageVersion(preKeyWhisperMessageBytes.slice(0, 1)),
message: message
};
},
encodePreKeyWhisperMessage: function (preKeyWhisperMessage) {
var message = preKeyWhisperMessage.message;
var messageBytes = new WhisperProtos.PreKeyWhisperMessage(message).encode().toArrayBuffer();
var versionField = getVersionField(preKeyWhisperMessage.version);
return ArrayBufferUtils.concat(versionField, messageBytes);
}
};
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var wrap = function (fn) {
return function () {
return Promise.resolve(fn.apply(this, arguments));
};
};
var PromiseInterfaceDecorator = function PromiseInterfaceDecorator(impl, methodNames) {
var $__0 = this;
methodNames.forEach(function (methodName) {
if (!impl[methodName]) {
throw new Error('interface must implement ' + methodName);
}
$__0[methodName] = wrap(impl[methodName]);
});
Object.freeze(this);
};
$traceurRuntime.createClass(PromiseInterfaceDecorator, {}, {});
var $__default = PromiseInterfaceDecorator;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__default = {
currentVersion: 3,
macByteCount: 8,
cipherKeyByteCount: 32,
macKeyByteCount: 32,
ivByteCount: 16,
dhKeyByteCount: 32,
rootKeyByteCount: 32,
chainKeyByteCount: 32,
maximumRetainedReceivedChainKeys: 5,
maximumMissedMessages: 2000,
maximumSessionStatesPerIdentity: 40
};
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__HKDF__, $__Chain__, $__ArrayBufferUtils__, $__ProtocolConstants__, $__co__;
var HKDF = ($__HKDF__ = _require(6), $__HKDF__ && $__HKDF__.__esModule && $__HKDF__ || { default: $__HKDF__ }).default;
var Chain = ($__Chain__ = _require(3), $__Chain__ && $__Chain__.__esModule && $__Chain__ || { default: $__Chain__ }).default;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var ProtocolConstants = ($__ProtocolConstants__ = _require(9), $__ProtocolConstants__ && $__ProtocolConstants__.__esModule && $__ProtocolConstants__ || { default: $__ProtocolConstants__ }).default;
var co = ($__co__ = _require(18), $__co__ && $__co__.__esModule && $__co__ || { default: $__co__ }).default;
var messageKeySeed = 1;
var chainKeySeed = 2;
var whisperMessageKeys = new Uint8Array([
87,
104,
105,
115,
112,
101,
114,
77,
101,
115,
115,
97,
103,
101,
75,
101,
121,
115
]).buffer;
var whisperRatchet = new Uint8Array([
87,
104,
105,
115,
112,
101,
114,
82,
97,
116,
99,
104,
101,
116
]).buffer;
var whisperText = new Uint8Array([
87,
104,
105,
115,
112,
101,
114,
84,
101,
120,
116
]).buffer;
var discontinuityBytes = new Uint8Array([
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255,
255
]).buffer;
function Ratchet(crypto) {
var self = this;
var hkdf = new HKDF(crypto);
this.deriveInitialRootKeyAndChain = co.wrap($traceurRuntime.initGeneratorFunction(function $__5(sessionVersion, agreements) {
var secrets, masterSecret, derivedSecret;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
secrets = [];
if (sessionVersion >= 3) {
secrets.push(discontinuityBytes);
}
secrets = secrets.concat(agreements);
masterSecret = ArrayBufferUtils.concat(secrets);
$ctx.state = 8;
break;
case 8:
$ctx.state = 2;
return hkdf.deriveSecrets(masterSecret, whisperText, ProtocolConstants.rootKeyByteCount + ProtocolConstants.chainKeyByteCount);
case 2:
derivedSecret = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = {
rootKey: derivedSecret.slice(0, ProtocolConstants.rootKeyByteCount),
chain: new Chain(derivedSecret.slice(ProtocolConstants.rootKeyByteCount))
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__5, this);
}));
this.deriveNextRootKeyAndChain = co.wrap($traceurRuntime.initGeneratorFunction(function $__6(rootKey, theirEphemeralPublicKey, ourEphemeralPrivateKey) {
var sharedSecret, derivedSecretBytes;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return crypto.calculateAgreement(theirEphemeralPublicKey, ourEphemeralPrivateKey);
case 2:
sharedSecret = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return hkdf.deriveSecretsWithSalt(sharedSecret, rootKey, whisperRatchet, ProtocolConstants.rootKeyByteCount + ProtocolConstants.chainKeyByteCount);
case 6:
derivedSecretBytes = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$ctx.returnValue = {
rootKey: derivedSecretBytes.slice(0, ProtocolConstants.rootKeyByteCount),
chain: new Chain(derivedSecretBytes.slice(ProtocolConstants.rootKeyByteCount))
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__6, this);
}));
this.clickSubRatchet = co.wrap($traceurRuntime.initGeneratorFunction(function $__7(chain) {
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
chain.index++;
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return deriveNextChainKey(chain.key);
case 2:
chain.key = $ctx.sent;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__7, this);
}));
this.deriveMessageKeys = co.wrap($traceurRuntime.initGeneratorFunction(function $__8(chainKey) {
var messageKey, keyMaterialBytes, cipherKeyBytes, macKeyBytes, ivBytes;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return deriveMessageKey(chainKey);
case 2:
messageKey = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return hkdf.deriveSecrets(messageKey, whisperMessageKeys, ProtocolConstants.cipherKeyByteCount + ProtocolConstants.macKeyByteCount + ProtocolConstants.ivByteCount);
case 6:
keyMaterialBytes = $ctx.sent;
$ctx.state = 8;
break;
case 8:
cipherKeyBytes = keyMaterialBytes.slice(0, ProtocolConstants.cipherKeyByteCount);
macKeyBytes = keyMaterialBytes.slice(ProtocolConstants.cipherKeyByteCount, ProtocolConstants.cipherKeyByteCount + ProtocolConstants.macKeyByteCount);
ivBytes = keyMaterialBytes.slice(ProtocolConstants.cipherKeyByteCount + ProtocolConstants.macKeyByteCount);
$ctx.state = 12;
break;
case 12:
$ctx.returnValue = {
cipherKey: cipherKeyBytes,
macKey: macKeyBytes,
iv: ivBytes
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__8, this);
}));
var hmacByte = co.wrap($traceurRuntime.initGeneratorFunction(function $__9(key, byte) {
var $__10, $__11, $__12, $__13, $__14;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__10 = crypto.hmac;
$__11 = ArrayBufferUtils.fromByte;
$__12 = $__11.call(ArrayBufferUtils, byte);
$__13 = $__10.call(crypto, key, $__12);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__13;
case 2:
$__14 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = $__14;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__9, this);
}));
var deriveMessageKey = co.wrap($traceurRuntime.initGeneratorFunction(function $__15(chainKey) {
var $__16, $__17;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__16 = hmacByte(chainKey, messageKeySeed);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__16;
case 2:
$__17 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = $__17;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__15, this);
}));
var deriveNextChainKey = co.wrap($traceurRuntime.initGeneratorFunction(function $__18(chainKey) {
var $__19, $__20;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__19 = hmacByte(chainKey, chainKeySeed);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__19;
case 2:
$__20 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = $__20;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__18, this);
}));
}
var $__default = Ratchet;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__ProtocolConstants__, $__ArrayBufferUtils__, $__SessionState__;
var ProtocolConstants = ($__ProtocolConstants__ = _require(9), $__ProtocolConstants__ && $__ProtocolConstants__.__esModule && $__ProtocolConstants__ || { default: $__ProtocolConstants__ }).default;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var SessionState = ($__SessionState__ = _require(14), $__SessionState__ && $__SessionState__.__esModule && $__SessionState__ || { default: $__SessionState__ }).default;
var Session = function Session(session) {
this.states = [];
if (session) {
for (var $__4 = session.states[$traceurRuntime.toProperty(Symbol.iterator)](), $__5 = void 0; !($__5 = $__4.next()).done;) {
var state = $__5.value;
{
this.states.push(new SessionState(state));
}
}
}
Object.seal(this);
};
$traceurRuntime.createClass(Session, {
mostRecentState: function () {
return this.states[0];
},
addState: function (state) {
this.states.unshift(state);
if (this.states.length > ProtocolConstants.maximumSessionStatesPerIdentity) {
this.states.pop();
}
},
removeState: function (state) {
var index = this.states.indexOf(state);
this.states.splice(index, 1);
}
}, {});
var $__default = Session;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__ArrayBufferUtils__, $__ProtocolConstants__, $__Messages__, $__SessionState__, $__Session__, $__Ratchet__, $__Exceptions__, $__co__;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var ProtocolConstants = ($__ProtocolConstants__ = _require(9), $__ProtocolConstants__ && $__ProtocolConstants__.__esModule && $__ProtocolConstants__ || { default: $__ProtocolConstants__ }).default;
var Messages = ($__Messages__ = _require(7), $__Messages__ && $__Messages__.__esModule && $__Messages__ || { default: $__Messages__ }).default;
var SessionState = ($__SessionState__ = _require(14), $__SessionState__ && $__SessionState__.__esModule && $__SessionState__ || { default: $__SessionState__ }).default;
var Session = ($__Session__ = _require(11), $__Session__ && $__Session__.__esModule && $__Session__ || { default: $__Session__ }).default;
var Ratchet = ($__Ratchet__ = _require(10), $__Ratchet__ && $__Ratchet__.__esModule && $__Ratchet__ || { default: $__Ratchet__ }).default;
var $__6 = ($__Exceptions__ = _require(5), $__Exceptions__ && $__Exceptions__.__esModule && $__Exceptions__ || { default: $__Exceptions__ }), InvalidMessageException = $__6.InvalidMessageException, DuplicateMessageException = $__6.DuplicateMessageException;
var co = ($__co__ = _require(18), $__co__ && $__co__.__esModule && $__co__ || { default: $__co__ }).default;
function SessionCipher(crypto) {
var self = this;
var ratchet = new Ratchet(crypto);
this.encryptMessage = co.wrap($traceurRuntime.initGeneratorFunction(function $__12(session, message) {
var newSession, whisperMessage;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
newSession = new Session(session);
$ctx.state = 15;
break;
case 15:
$ctx.state = 2;
return createWhisperMessage(newSession, message);
case 2:
whisperMessage = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return ratchet.clickSubRatchet(newSession.mostRecentState().sendingChain);
case 6:
$ctx.maybeThrow();
$ctx.state = 8;
break;
case 8:
$ctx.state = newSession.mostRecentState().pendingPreKey ? 9 : 11;
break;
case 9:
$ctx.returnValue = {
isPreKeyWhisperMessage: true,
body: createPreKeyWhisperMessage(newSession, whisperMessage),
session: newSession
};
$ctx.state = -2;
break;
case 11:
$ctx.returnValue = {
isPreKeyWhisperMessage: false,
body: whisperMessage,
session: newSession
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__12, this);
}));
this.decryptPreKeyWhisperMessage = function (session, preKeyWhisperMessageBytes) {
var preKeyWhisperMessage = Messages.decodePreKeyWhisperMessage(preKeyWhisperMessageBytes);
return self.decryptWhisperMessage(session, preKeyWhisperMessage.message.message);
};
this.decryptWhisperMessage = co.wrap($traceurRuntime.initGeneratorFunction(function $__13(session, whisperMessageBytes) {
var newSession, exceptions, $__8, $__9, state, clonedSessionState, promise, result, messages;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
newSession = new Session(session);
exceptions = [];
$ctx.state = 17;
break;
case 17:
$__8 = newSession.states[$traceurRuntime.toProperty(Symbol.iterator)](), $__9 = void 0;
$ctx.state = 6;
break;
case 6:
$ctx.state = !($__9 = $__8.next()).done ? 12 : 14;
break;
case 12:
state = $__9.value;
$ctx.state = 13;
break;
case 13:
clonedSessionState = new SessionState(state);
promise = decryptWhisperMessageWithSessionState(clonedSessionState, whisperMessageBytes);
$ctx.state = 11;
break;
case 11:
$ctx.state = 2;
return promise.catch(function (e) {
exceptions.push(e);
});
case 2:
result = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = result !== undefined ? 7 : 6;
break;
case 7:
newSession.removeState(state);
newSession.addState(clonedSessionState);
$ctx.state = 8;
break;
case 8:
$ctx.returnValue = {
message: result,
session: newSession
};
$ctx.state = -2;
break;
case 14:
messages = exceptions.map(function (e) {
return e.toString();
});
throw new InvalidMessageException('Unable to decrypt message: ' + messages);
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__13, this);
}));
var decryptWhisperMessageWithSessionState = co.wrap($traceurRuntime.initGeneratorFunction(function $__14(sessionState, whisperMessageBytes) {
var whisperMessage, macInputTypes, message, theirEphemeralPublicKey, receivingChain, messageKeys, isValid, plaintext;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
whisperMessage = Messages.decodeWhisperMessage(whisperMessageBytes);
macInputTypes = Messages.decodeWhisperMessageMacInput(whisperMessageBytes);
if (whisperMessage.version.current !== sessionState.sessionVersion) {
throw new InvalidMessageException('Message version doesn\'t match session version');
}
message = whisperMessage.message;
theirEphemeralPublicKey = message.ratchetKey;
$ctx.state = 20;
break;
case 20:
$ctx.state = 2;
return getOrCreateReceivingChain(sessionState, theirEphemeralPublicKey);
case 2:
receivingChain = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return getOrCreateMessageKeys(theirEphemeralPublicKey, receivingChain, message.counter);
case 6:
messageKeys = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$ctx.state = 10;
return isValidMac(macInputTypes, messageKeys.macKey, whisperMessage.version.current, sessionState.remoteIdentityKey, sessionState.localIdentityKey, whisperMessage.mac);
case 10:
isValid = $ctx.sent;
$ctx.state = 12;
break;
case 12:
if (!isValid) {
throw new InvalidMessageException('Bad mac');
}
$ctx.state = 22;
break;
case 22:
$ctx.state = 14;
return crypto.decrypt(messageKeys.cipherKey, message.ciphertext, messageKeys.iv);
case 14:
plaintext = $ctx.sent;
$ctx.state = 16;
break;
case 16:
sessionState.pendingPreKey = null;
$ctx.state = 24;
break;
case 24:
$ctx.returnValue = plaintext;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__14, this);
}));
var isValidMac = co.wrap($traceurRuntime.initGeneratorFunction(function $__15(data, macKey, messageVersion, senderIdentityKey, receiverIdentityKey, theirMac) {
var ourMac;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return getMac(data, macKey, messageVersion, senderIdentityKey, receiverIdentityKey);
case 2:
ourMac = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = ArrayBufferUtils.areEqual(ourMac, theirMac);
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__15, this);
}));
var getMac = co.wrap($traceurRuntime.initGeneratorFunction(function $__16(data, macKey, messageVersion, senderIdentityKey, receiverIdentityKey) {
var macInputs, macBytes;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
macInputs = messageVersion >= 3 ? [
senderIdentityKey,
receiverIdentityKey
] : [];
macInputs.push(data);
$ctx.state = 8;
break;
case 8:
$ctx.state = 2;
return crypto.hmac(macKey, ArrayBufferUtils.concat(macInputs));
case 2:
macBytes = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = macBytes.slice(0, ProtocolConstants.macByteCount);
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__16, this);
}));
var createWhisperMessage = co.wrap($traceurRuntime.initGeneratorFunction(function $__17(session, paddedMessage) {
var messageKeys, ciphertext, version, message, macInputBytes, $__18, $__19, $__20, $__21, $__22, $__23, $__24, $__25, $__26, $__27, $__28, $__29, $__30, $__31, $__32;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return ratchet.deriveMessageKeys(session.mostRecentState().sendingChain.key);
case 2:
messageKeys = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$ctx.state = 6;
return crypto.encrypt(messageKeys.cipherKey, paddedMessage, messageKeys.iv);
case 6:
ciphertext = $ctx.sent;
$ctx.state = 8;
break;
case 8:
version = {
current: session.mostRecentState().sessionVersion,
max: ProtocolConstants.currentVersion
};
message = {
ratchetKey: session.mostRecentState().senderRatchetKeyPair.public,
counter: session.mostRecentState().sendingChain.index,
previousCounter: session.mostRecentState().previousCounter,
ciphertext: ciphertext
};
macInputBytes = Messages.encodeWhisperMessageMacInput({
version: version,
message: message
});
$ctx.state = 20;
break;
case 20:
$__18 = Messages.encodeWhisperMessage;
$__19 = messageKeys.macKey;
$__20 = session.mostRecentState;
$__21 = $__20.call(session);
$__22 = $__21.sessionVersion;
$__23 = session.mostRecentState;
$__24 = $__23.call(session);
$__25 = $__24.localIdentityKey;
$__26 = session.mostRecentState;
$__27 = $__26.call(session);
$__28 = $__27.remoteIdentityKey;
$__29 = getMac(macInputBytes, $__19, $__22, $__25, $__28);
$ctx.state = 14;
break;
case 14:
$ctx.state = 10;
return $__29;
case 10:
$__30 = $ctx.sent;
$ctx.state = 12;
break;
case 12:
$__31 = {
version: version,
message: message,
mac: $__30
};
$__32 = $__18.call(Messages, $__31);
$ctx.state = 16;
break;
case 16:
$ctx.returnValue = $__32;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__17, this);
}));
var createPreKeyWhisperMessage = function (session, whisperMessage) {
var pendingPreKey = session.mostRecentState().pendingPreKey;
return Messages.encodePreKeyWhisperMessage({
version: {
current: session.mostRecentState().sessionVersion,
max: ProtocolConstants.currentVersion
},
message: {
registrationId: session.mostRecentState().localRegistrationId,
preKeyId: pendingPreKey.preKeyId,
signedPreKeyId: pendingPreKey.signedPreKeyId,
baseKey: pendingPreKey.baseKey,
identityKey: session.mostRecentState().localIdentityKey,
message: whisperMessage
}
});
};
var getOrCreateReceivingChain = co.wrap($traceurRuntime.initGeneratorFunction(function $__33(sessionState, theirEphemeralPublicKey) {
var chain, $__34, $__35;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
chain = sessionState.findReceivingChain(theirEphemeralPublicKey);
$ctx.state = 13;
break;
case 13:
$ctx.state = chain ? 1 : 2;
break;
case 1:
$ctx.returnValue = chain;
$ctx.state = -2;
break;
case 2:
$__34 = clickMainRatchet(sessionState, theirEphemeralPublicKey);
$ctx.state = 9;
break;
case 9:
$ctx.state = 5;
return $__34;
case 5:
$__35 = $ctx.sent;
$ctx.state = 7;
break;
case 7:
$ctx.returnValue = $__35;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__33, this);
}));
var getOrCreateMessageKeys = co.wrap($traceurRuntime.initGeneratorFunction(function $__36(theirEphemeralPublicKey, chain, counter) {
var cachedMessageKeys, messageKeys;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = chain.index > counter ? 3 : 24;
break;
case 3:
cachedMessageKeys = chain.messageKeys[counter];
if (!cachedMessageKeys) {
throw new DuplicateMessageException('Received message with old counter');
}
delete chain.messageKeys[counter];
$ctx.state = 4;
break;
case 4:
$ctx.returnValue = cachedMessageKeys;
$ctx.state = -2;
break;
case 24:
if (counter - chain.index > ProtocolConstants.maximumMissedMessages) {
throw new InvalidMessageException('Too many skipped messages');
}
$ctx.state = 25;
break;
case 25:
$ctx.state = chain.index < counter ? 5 : 13;
break;
case 5:
$ctx.state = 6;
return ratchet.deriveMessageKeys(chain.key);
case 6:
chain.messageKeys[chain.index] = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$ctx.state = 10;
return ratchet.clickSubRatchet(chain);
case 10:
$ctx.maybeThrow();
$ctx.state = 25;
break;
case 13:
$ctx.state = 15;
return ratchet.deriveMessageKeys(chain.key);
case 15:
messageKeys = $ctx.sent;
$ctx.state = 17;
break;
case 17:
$ctx.state = 19;
return ratchet.clickSubRatchet(chain);
case 19:
$ctx.maybeThrow();
$ctx.state = 21;
break;
case 21:
$ctx.returnValue = messageKeys;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__36, this);
}));
var clickMainRatchet = co.wrap($traceurRuntime.initGeneratorFunction(function $__37(sessionState, theirEphemeralPublicKey) {
var $__10, theirRootKey, nextReceivingChain, ourNewEphemeralKeyPair, $__11, rootKey, nextSendingChain, $__38, $__39, $__40, $__41, $__42, $__43, $__44, $__45, $__46, $__47, $__48, $__49, $__50, $__51;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$__38 = ratchet.deriveNextRootKeyAndChain;
$__39 = sessionState.rootKey;
$__40 = sessionState.senderRatchetKeyPair;
$__41 = $__40.private;
$__42 = $__38.call(ratchet, $__39, theirEphemeralPublicKey, $__41);
$ctx.state = 6;
break;
case 6:
$ctx.state = 2;
return $__42;
case 2:
$__43 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__10 = $__43;
$__44 = $__10.rootKey;
theirRootKey = $__44;
$__45 = $__10.chain;
nextReceivingChain = $__45;
$ctx.state = 8;
break;
case 8:
$ctx.state = 10;
return crypto.generateKeyPair();
case 10:
ourNewEphemeralKeyPair = $ctx.sent;
$ctx.state = 12;
break;
case 12:
$__46 = ratchet.deriveNextRootKeyAndChain;
$__47 = ourNewEphemeralKeyPair.private;
$__48 = $__46.call(ratchet, theirRootKey, theirEphemeralPublicKey, $__47);
$ctx.state = 18;
break;
case 18:
$ctx.state = 14;
return $__48;
case 14:
$__49 = $ctx.sent;
$ctx.state = 16;
break;
case 16:
$__11 = $__49;
$__50 = $__11.rootKey;
rootKey = $__50;
$__51 = $__11.chain;
nextSendingChain = $__51;
$ctx.state = 20;
break;
case 20:
sessionState.rootKey = rootKey;
sessionState.addReceivingChain(theirEphemeralPublicKey, nextReceivingChain);
sessionState.previousCounter = Math.max(sessionState.sendingChain.index - 1, 0);
sessionState.sendingChain = nextSendingChain;
sessionState.senderRatchetKeyPair = ourNewEphemeralKeyPair;
$ctx.state = 24;
break;
case 24:
$ctx.returnValue = nextReceivingChain;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__37, this);
}));
Object.freeze(self);
}
var $__default = SessionCipher;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__WhisperProtos__, $__ArrayBufferUtils__, $__Messages__, $__Ratchet__, $__SessionState__, $__Session__, $__Exceptions__, $__co__;
var WhisperProtos = ($__WhisperProtos__ = _require(16), $__WhisperProtos__ && $__WhisperProtos__.__esModule && $__WhisperProtos__ || { default: $__WhisperProtos__ }).default;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var Messages = ($__Messages__ = _require(7), $__Messages__ && $__Messages__.__esModule && $__Messages__ || { default: $__Messages__ }).default;
var Ratchet = ($__Ratchet__ = _require(10), $__Ratchet__ && $__Ratchet__.__esModule && $__Ratchet__ || { default: $__Ratchet__ }).default;
var SessionState = ($__SessionState__ = _require(14), $__SessionState__ && $__SessionState__.__esModule && $__SessionState__ || { default: $__SessionState__ }).default;
var Session = ($__Session__ = _require(11), $__Session__ && $__Session__.__esModule && $__Session__ || { default: $__Session__ }).default;
var $__6 = ($__Exceptions__ = _require(5), $__Exceptions__ && $__Exceptions__.__esModule && $__Exceptions__ || { default: $__Exceptions__ }), InvalidKeyException = $__6.InvalidKeyException, UnsupportedProtocolVersionException = $__6.UnsupportedProtocolVersionException, UntrustedIdentityException = $__6.UntrustedIdentityException;
var co = ($__co__ = _require(18), $__co__ && $__co__.__esModule && $__co__ || { default: $__co__ }).default;
function SessionFactory(crypto, store) {
var self = this;
var ratchet = new Ratchet(crypto);
self.createSessionFromPreKeyBundle = co.wrap($traceurRuntime.initGeneratorFunction(function $__12(retrievedPreKeyBundle) {
var validSignature, supportsV3, ourBaseKeyPair, theirSignedPreKey, aliceParameters, sessionState, session, $__13, $__14, $__15, $__16, $__17, $__18, $__19;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = retrievedPreKeyBundle.signedPreKey ? 1 : 6;
break;
case 1:
$ctx.state = 2;
return crypto.verifySignature(retrievedPreKeyBundle.identityKey, retrievedPreKeyBundle.signedPreKey, retrievedPreKeyBundle.signedPreKeySignature);
case 2:
validSignature = $ctx.sent;
$ctx.state = 4;
break;
case 4:
if (!validSignature) {
throw new InvalidKeyException('Invalid signature on device key');
}
$ctx.state = 6;
break;
case 6:
if (!retrievedPreKeyBundle.preKey && !retrievedPreKeyBundle.signedPreKey) {
throw new InvalidKeyException('Both signed and unsigned pre keys are absent');
}
supportsV3 = !!retrievedPreKeyBundle.signedPreKey;
$ctx.state = 31;
break;
case 31:
$ctx.state = 9;
return crypto.generateKeyPair();
case 9:
ourBaseKeyPair = $ctx.sent;
$ctx.state = 11;
break;
case 11:
theirSignedPreKey = supportsV3 ? retrievedPreKeyBundle.signedPreKey : retrievedPreKeyBundle.preKey;
$ctx.state = 33;
break;
case 33:
$__13 = store.getLocalIdentityKeyPair;
$__14 = $__13.call(store);
$ctx.state = 17;
break;
case 17:
$ctx.state = 13;
return $__14;
case 13:
$__15 = $ctx.sent;
$ctx.state = 15;
break;
case 15:
$__16 = retrievedPreKeyBundle.identityKey;
if (supportsV3) {
$__17 = retrievedPreKeyBundle.preKey;
$__18 = $__17;
} else {
$__18 = undefined;
}
$__19 = {
sessionVersion: supportsV3 ? 3 : 2,
ourBaseKeyPair: ourBaseKeyPair,
ourIdentityKeyPair: $__15,
theirIdentityKey: $__16,
theirSignedPreKey: theirSignedPreKey,
theirRatchetKey: theirSignedPreKey,
theirOneTimePreKey: $__18
};
aliceParameters = $__19;
$ctx.state = 19;
break;
case 19:
$ctx.state = 21;
return initializeAliceSession(aliceParameters);
case 21:
sessionState = $ctx.sent;
$ctx.state = 23;
break;
case 23:
sessionState.pendingPreKey = {
preKeyId: supportsV3 ? retrievedPreKeyBundle.preKeyId : null,
signedPreKeyId: retrievedPreKeyBundle.signedPreKeyId,
baseKey: ourBaseKeyPair.public
};
$ctx.state = 35;
break;
case 35:
$ctx.state = 25;
return store.getLocalRegistrationId();
case 25:
sessionState.localRegistrationId = $ctx.sent;
$ctx.state = 27;
break;
case 27:
session = new Session();
session.addState(sessionState);
$ctx.state = 37;
break;
case 37:
$ctx.returnValue = session;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__12, this);
}));
self.createSessionFromPreKeyWhisperMessage = co.wrap($traceurRuntime.initGeneratorFunction(function $__20(session, preKeyWhisperMessageBytes) {
var preKeyWhisperMessage, message, $__8, $__9, cachedSessionState, ourSignedPreKeyPair, preKeyPair, bobParameters, sessionState, clonedSession, $__21, $__22, $__23, $__24, $__25, $__26, $__27, $__28;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
preKeyWhisperMessage = Messages.decodePreKeyWhisperMessage(preKeyWhisperMessageBytes);
if (preKeyWhisperMessage.version.current !== 3) {
throw new UnsupportedProtocolVersionException('Protocol version ' + preKeyWhisperMessage.version.current + ' is not supported');
}
message = preKeyWhisperMessage.message;
$ctx.state = 33;
break;
case 33:
$ctx.state = session ? 7 : 6;
break;
case 7:
$__8 = session.states[$traceurRuntime.toProperty(Symbol.iterator)](), $__9 = void 0;
$ctx.state = 2;
break;
case 2:
$ctx.state = !($__9 = $__8.next()).done ? 4 : 6;
break;
case 4:
cachedSessionState = $__9.value;
$ctx.state = 5;
break;
case 5:
$ctx.state = cachedSessionState.theirBaseKey && ArrayBufferUtils.areEqual(cachedSessionState.theirBaseKey, message.baseKey) ? 1 : 2;
break;
case 1:
$ctx.returnValue = {
session: session,
identityKey: message.identityKey,
registrationId: message.registrationId
};
$ctx.state = -2;
break;
case 6:
$ctx.state = 10;
return store.getLocalSignedPreKeyPair(message.signedPreKeyId);
case 10:
ourSignedPreKeyPair = $ctx.sent;
$ctx.state = 12;
break;
case 12:
$ctx.state = message.preKeyId !== null ? 13 : 16;
break;
case 13:
$ctx.state = 14;
return store.getLocalPreKeyPair(message.preKeyId);
case 14:
preKeyPair = $ctx.sent;
$ctx.state = 16;
break;
case 16:
$__21 = preKeyWhisperMessage.version;
$__22 = $__21.current;
$__23 = message.baseKey;
$__24 = message.identityKey;
$__25 = store.getLocalIdentityKeyPair;
$__26 = $__25.call(store);
$ctx.state = 23;
break;
case 23:
$ctx.state = 19;
return $__26;
case 19:
$__27 = $ctx.sent;
$ctx.state = 21;
break;
case 21:
$__28 = {
sessionVersion: $__22,
theirBaseKey: $__23,
theirIdentityKey: $__24,
ourIdentityKeyPair: $__27,
ourSignedPreKeyPair: ourSignedPreKeyPair,
ourRatchetKeyPair: ourSignedPreKeyPair,
ourOneTimePreKeyPair: preKeyPair
};
bobParameters = $__28;
$ctx.state = 25;
break;
case 25:
$ctx.state = 27;
return initializeBobSession(bobParameters);
case 27:
sessionState = $ctx.sent;
$ctx.state = 29;
break;
case 29:
sessionState.theirBaseKey = message.baseKey;
clonedSession = new Session(session);
clonedSession.addState(sessionState);
$ctx.state = 35;
break;
case 35:
$ctx.returnValue = {
session: clonedSession,
identityKey: message.identityKey,
registrationId: message.registrationId
};
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__20, this);
}));
var initializeAliceSession = co.wrap($traceurRuntime.initGeneratorFunction(function $__29(parameters) {
var sendingRatchetKeyPair, agreements, $__10, theirRootKey, receivingChain, $__11, rootKey, sendingChain, sessionState, $__30, $__31, $__32, $__33, $__34, $__35, $__36, $__37, $__38, $__39, $__40, $__41, $__42, $__43;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
$ctx.state = 2;
return crypto.generateKeyPair();
case 2:
sendingRatchetKeyPair = $ctx.sent;
$ctx.state = 4;
break;
case 4:
agreements = [
crypto.calculateAgreement(parameters.theirSignedPreKey, parameters.ourIdentityKeyPair.private),
crypto.calculateAgreement(parameters.theirIdentityKey, parameters.ourBaseKeyPair.private),
crypto.calculateAgreement(parameters.theirSignedPreKey, parameters.ourBaseKeyPair.private)
];
if (parameters.sessionVersion >= 3 && parameters.theirOneTimePreKey) {
agreements.push(crypto.calculateAgreement(parameters.theirOneTimePreKey, parameters.ourBaseKeyPair.private));
}
$ctx.state = 30;
break;
case 30:
$__30 = ratchet.deriveInitialRootKeyAndChain;
$__31 = parameters.sessionVersion;
$ctx.state = 14;
break;
case 14:
$ctx.state = 6;
return agreements;
case 6:
$__32 = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$__33 = $__30.call(ratchet, $__31, $__32);
$ctx.state = 16;
break;
case 16:
$ctx.state = 10;
return $__33;
case 10:
$__34 = $ctx.sent;
$ctx.state = 12;
break;
case 12:
$__10 = $__34;
$__35 = $__10.rootKey;
theirRootKey = $__35;
$__36 = $__10.chain;
receivingChain = $__36;
$ctx.state = 18;
break;
case 18:
$__37 = ratchet.deriveNextRootKeyAndChain;
$__38 = parameters.theirRatchetKey;
$__39 = sendingRatchetKeyPair.private;
$__40 = $__37.call(ratchet, theirRootKey, $__38, $__39);
$ctx.state = 24;
break;
case 24:
$ctx.state = 20;
return $__40;
case 20:
$__41 = $ctx.sent;
$ctx.state = 22;
break;
case 22:
$__11 = $__41;
$__42 = $__11.rootKey;
rootKey = $__42;
$__43 = $__11.chain;
sendingChain = $__43;
$ctx.state = 26;
break;
case 26:
sessionState = new SessionState({
sessionVersion: parameters.sessionVersion,
remoteIdentityKey: parameters.theirIdentityKey,
localIdentityKey: parameters.ourIdentityKeyPair.public,
rootKey: rootKey,
sendingChain: sendingChain,
senderRatchetKeyPair: sendingRatchetKeyPair
});
sessionState.addReceivingChain(parameters.theirRatchetKey, receivingChain);
$ctx.state = 32;
break;
case 32:
$ctx.returnValue = sessionState;
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__29, this);
}));
var initializeBobSession = co.wrap($traceurRuntime.initGeneratorFunction(function $__44(parameters) {
var agreements, $__10, rootKey, sendingChain, $__45, $__46, $__47, $__48, $__49, $__50, $__51;
return $traceurRuntime.createGeneratorInstance(function ($ctx) {
while (true)
switch ($ctx.state) {
case 0:
agreements = [
crypto.calculateAgreement(parameters.theirIdentityKey, parameters.ourSignedPreKeyPair.private),
crypto.calculateAgreement(parameters.theirBaseKey, parameters.ourIdentityKeyPair.private),
crypto.calculateAgreement(parameters.theirBaseKey, parameters.ourSignedPreKeyPair.private)
];
if (parameters.sessionVersion >= 3 && parameters.ourOneTimePreKeyPair) {
agreements.push(crypto.calculateAgreement(parameters.theirBaseKey, parameters.ourOneTimePreKeyPair.private));
}
$ctx.state = 18;
break;
case 18:
$__45 = ratchet.deriveInitialRootKeyAndChain;
$__46 = parameters.sessionVersion;
$ctx.state = 10;
break;
case 10:
$ctx.state = 2;
return agreements;
case 2:
$__47 = $ctx.sent;
$ctx.state = 4;
break;
case 4:
$__48 = $__45.call(ratchet, $__46, $__47);
$ctx.state = 12;
break;
case 12:
$ctx.state = 6;
return $__48;
case 6:
$__49 = $ctx.sent;
$ctx.state = 8;
break;
case 8:
$__10 = $__49;
$__50 = $__10.rootKey;
rootKey = $__50;
$__51 = $__10.chain;
sendingChain = $__51;
$ctx.state = 14;
break;
case 14:
$ctx.returnValue = new SessionState({
sessionVersion: parameters.sessionVersion,
remoteIdentityKey: parameters.theirIdentityKey,
localIdentityKey: parameters.ourIdentityKeyPair.public,
rootKey: rootKey,
sendingChain: sendingChain,
senderRatchetKeyPair: parameters.ourRatchetKeyPair
});
$ctx.state = -2;
break;
default:
return $ctx.end();
}
}, $__44, this);
}));
Object.freeze(self);
}
var $__default = SessionFactory;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__ArrayBufferUtils__, $__ProtocolConstants__;
var ArrayBufferUtils = ($__ArrayBufferUtils__ = _require(1), $__ArrayBufferUtils__ && $__ArrayBufferUtils__.__esModule && $__ArrayBufferUtils__ || { default: $__ArrayBufferUtils__ }).default;
var ProtocolConstants = ($__ProtocolConstants__ = _require(9), $__ProtocolConstants__ && $__ProtocolConstants__.__esModule && $__ProtocolConstants__ || { default: $__ProtocolConstants__ }).default;
var makeReadonly = function (obj, key) {
Object.defineProperty(obj, key, { writable: false });
};
var SessionState = function SessionState(parameters) {
Object.assign(this, {
sessionVersion: 3,
remoteIdentityKey: null,
localIdentityKey: null,
pendingPreKey: null,
localRegistrationId: 0,
theirBaseKey: null,
rootKey: null,
sendingChain: null,
senderRatchetKeyPair: null,
receivingChains: [],
previousCounter: 0
}, parameters);
makeReadonly(this, 'sessionVersion');
makeReadonly(this, 'remoteIdentityKey');
makeReadonly(this, 'localIdentityKey');
Object.seal(this);
};
$traceurRuntime.createClass(SessionState, {
findReceivingChain: function (theirEphemeralPublicKey) {
for (var i = 0; i < this.receivingChains.length; i++) {
var receivingChain = this.receivingChains[i];
if (ArrayBufferUtils.areEqual(receivingChain.theirEphemeralKey, theirEphemeralPublicKey)) {
return receivingChain.chain;
}
}
return null;
},
addReceivingChain: function (theirEphemeralPublicKey, chain) {
this.receivingChains.push({
theirEphemeralKey: theirEphemeralPublicKey,
chain: chain
});
if (this.receivingChains.length > ProtocolConstants.maximumRetainedReceivedChainKeys) {
this.receivingChains.shift();
}
}
}, {});
var $__default = SessionState;
},
function (module, exports) {
'use strict';
Object.defineProperties(module.exports, {
default: {
get: function () {
return $__default;
}
},
__esModule: { value: true }
});
var $__PromiseInterfaceDecorator__;
var PromiseInterfaceDecorator = ($__PromiseInterfaceDecorator__ = _require(8), $__PromiseInterfaceDecorator__ && $__PromiseInterfaceDecorator__.__esModule && $__PromiseInterfaceDecorator__ || { default: $__PromiseInterfaceDecorator__ }).default;
var methodNames = [
'getLocalIdentityKeyPair',
'getLocalRegistrationId',
'getLocalSignedPreKeyPair',
'getLocalPreKeyPair'
];
var Store = function Store(store) {
$traceurRuntime.superConstructor($Store).call(this, store, methodNames);
};
var $Store = Store;
$traceurRuntime.createClass(Store, {}, {}, PromiseInterfaceDecorator);
var $__default = Store;
},
function (module, exports) {
'use strict';
module.exports = _require(19).newBuilder({})['import']({
'package': 'textsecure',
'messages': [
{
'name': 'WhisperMessage',
'fields': [
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'ratchetKey',
'id': 1
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'counter',
'id': 2
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'previousCounter',
'id': 3
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'ciphertext',
'id': 4
}
],
'enums': [],
'messages': [],
'options': {},
'oneofs': {}
},
{
'name': 'PreKeyWhisperMessage',
'fields': [
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'registrationId',
'id': 5
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'preKeyId',
'id': 1
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'signedPreKeyId',
'id': 6
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'baseKey',
'id': 2
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'identityKey',
'id': 3
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'message',
'id': 4
}
],
'enums': [],
'messages': [],
'options': {},
'oneofs': {}
},
{
'name': 'KeyExchangeMessage',
'fields': [
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'id',
'id': 1
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'baseKey',
'id': 2
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'ratchetKey',
'id': 3
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'identityKey',
'id': 4
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'baseKeySignature',
'id': 5
}
],
'enums': [],
'messages': [],
'options': {},
'oneofs': {}
},
{
'name': 'SenderKeyMessage',
'fields': [
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'id',
'id': 1
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'iteration',
'id': 2
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'ciphertext',
'id': 3
}
],
'enums': [],
'messages': [],
'options': {},
'oneofs': {}
},
{
'name': 'SenderKeyDistributionMessage',
'fields': [
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'id',
'id': 1
},
{
'rule': 'optional',
'options': {},
'type': 'uint32',
'name': 'iteration',
'id': 2
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'chainKey',
'id': 3
},
{
'rule': 'optional',
'options': {},
'type': 'bytes',
'name': 'signingKey',
'id': 4
}
],
'enums': [],
'messages': [],
'options': {},
'oneofs': {}
}
],
'enums': [],
'imports': [],
'options': {
'java_package': 'org.whispersystems.libaxolotl.protocol',
'java_outer_classname': 'WhisperProtos'
},
'services': []
}).build('textsecure');
},
function (module, exports) {
module.exports = __external_axolotlCrypto;
},
function (module, exports) {
var slice = Array.prototype.slice;
module.exports = co['default'] = co.co = co;
co.wrap = function (fn) {
return function () {
return co.call(this, fn.apply(this, arguments));
};
};
function co(gen) {
var ctx = this;
if (typeof gen === 'function')
gen = gen.call(this);
return new Promise(function (resolve, reject) {
onFulfilled();
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
}
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}
function next(ret) {
if (ret.done)
return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value))
return value.then(onFulfilled, onRejected);
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"'));
}
});
}
function toPromise(obj) {
if (!obj)
return obj;
if (isPromise(obj))
return obj;
if (isGeneratorFunction(obj) || isGenerator(obj))
return co.call(this, obj);
if ('function' == typeof obj)
return thunkToPromise.call(this, obj);
if (Array.isArray(obj))
return arrayToPromise.call(this, obj);
if (isObject(obj))
return objectToPromise.call(this, obj);
return obj;
}
function thunkToPromise(fn) {
var ctx = this;
return new Promise(function (resolve, reject) {
fn.call(ctx, function (err, res) {
if (err)
return reject(err);
if (arguments.length > 2)
res = slice.call(arguments, 1);
resolve(res);
});
});
}
function arrayToPromise(obj) {
return Promise.all(obj.map(toPromise, this));
}
function objectToPromise(obj) {
var results = new obj.constructor();
var keys = Object.keys(obj);
var promises = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var promise = toPromise.call(this, obj[key]);
if (promise && isPromise(promise))
defer(promise, key);
else
results[key] = obj[key];
}
return Promise.all(promises).then(function () {
return results;
});
function defer(promise, key) {
results[key] = undefined;
promises.push(promise.then(function (res) {
results[key] = res;
}));
}
}
function isPromise(obj) {
return 'function' == typeof obj.then;
}
function isGenerator(obj) {
return 'function' == typeof obj.next && 'function' == typeof obj.throw;
}
function isGeneratorFunction(obj) {
var constructor = obj.constructor;
var proto = constructor.prototype;
var name = constructor.displayName || constructor.name;
var nameLooksRight = 'GeneratorFunction' == name;
var methodsLooksRight = 'function' == typeof proto.next && 'function' == typeof proto.throw;
return nameLooksRight || methodsLooksRight;
}
function isObject(val) {
return Object == val.constructor;
}
},
function (module, exports) {
module.exports = __external_1;
}
];
return _require(0);
}));