Update libsignal-protocol v1.0.0

// FREEBIE
This commit is contained in:
lilia 2016-06-06 16:48:39 -07:00
parent d89c3e8e86
commit b8fddfbbdd
3 changed files with 18370 additions and 18570 deletions

View file

@ -25133,21 +25133,7 @@ run();
/* vim: ts=4:sw=4:expandtab /* vim: ts=4:sw=4:expandtab */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
(function() { (function() {
@ -25173,7 +25159,7 @@ var Internal = Internal || {};
var priv = new Uint8Array(privKey); var priv = new Uint8Array(privKey);
priv[0] &= 248; priv[0] &= 248;
priv[31] &= 127; priv[31] &= 127;
priv[31] |= 64 priv[31] |= 64;
// Where to store the result // Where to store the result
var publicKey_ptr = Module._malloc(32); var publicKey_ptr = Module._malloc(32);

View file

@ -25257,21 +25257,7 @@ run();
/* vim: ts=4:sw=4:expandtab /* vim: ts=4:sw=4:expandtab */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
(function() { (function() {
@ -25297,7 +25283,7 @@ var Internal = Internal || {};
var priv = new Uint8Array(privKey); var priv = new Uint8Array(privKey);
priv[0] &= 248; priv[0] &= 248;
priv[31] &= 127; priv[31] &= 127;
priv[31] |= 64 priv[31] |= 64;
// Where to store the result // Where to store the result
var publicKey_ptr = Module._malloc(32); var publicKey_ptr = Module._malloc(32);
@ -35315,7 +35301,7 @@ Curve25519Worker.prototype = {
return curve25519.verify(pubKey, msg, sig); return curve25519.verify(pubKey, msg, sig);
} }
}; };
}; }
Internal.Curve = wrapCurve25519(Internal.curve25519); Internal.Curve = wrapCurve25519(Internal.curve25519);
Internal.Curve.async = wrapCurve25519(Internal.curve25519_async); Internal.Curve.async = wrapCurve25519(Internal.curve25519_async);
@ -35346,21 +35332,8 @@ Curve25519Worker.prototype = {
})(); })();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
(function() { (function() {
@ -35487,63 +35460,21 @@ var Internal = Internal || {};
})(); })();
/* vim: ts=4:sw=4 /*
* * vim: ts=4:sw=4
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
var util = (function() { var util = (function() {
'use strict'; 'use strict';
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
var StaticArrayBufferProto = new ArrayBuffer().__proto__; var StaticArrayBufferProto = new ArrayBuffer().__proto__;
var StaticUint8ArrayProto = new Uint8Array().__proto__;
function stringObject(thing) {
if (typeof thing === 'string') {
return thing;
}
if (thing === Object(thing)) {
if (thing.__proto__ == StaticUint8ArrayProto) {
return String.fromCharCode.apply(null, thing);
}
if (thing.__proto__ == StaticArrayBufferProto) {
return stringObject(new Uint8Array(thing));
}
if (thing.__proto__ == StaticByteBufferProto) {
return thing.toString('binary');
}
}
throw new Error('unsure how to stringify object of type ' + typeof thing);
}
return { return {
toString: function(thing) { toString: function(thing) {
if (typeof thing == 'string') { if (typeof thing == 'string') {
return thing; return thing;
} else if (util.isStringable(thing)) {
return util.stringObject(thing);
} else {
throw new Error("Unsure how to convert object to string from type " + typeof thing);
} }
}, return new dcodeIO.ByteBuffer.wrap(thing).toString('binary');
stringObject: stringObject,
isStringable: function (thing) {
return (thing === Object(thing) &&
(thing.__proto__ == StaticArrayBufferProto ||
thing.__proto__ == StaticUint8ArrayProto ||
thing.__proto__ == StaticByteBufferProto));
}, },
toArrayBuffer: function(thing) { toArrayBuffer: function(thing) {
if (thing === undefined) { if (thing === undefined) {
@ -35553,42 +35484,23 @@ var util = (function() {
if (thing.__proto__ == StaticArrayBufferProto) { if (thing.__proto__ == StaticArrayBufferProto) {
return thing; return thing;
} }
//TODO: Several more cases here...
}
if (thing instanceof Array) {
// Assuming Uint16Array from curve25519
//TODO: Move to convertToArrayBuffer
var res = new ArrayBuffer(thing.length * 2);
var uint = new Uint16Array(res);
for (var i = 0; i < thing.length; i++) {
uint[i] = thing[i];
}
return res;
} }
var str; var str;
if (util.isStringable(thing)) { if (typeof thing == "string") {
str = util.stringObject(thing);
} else if (typeof thing == "string") {
str = thing; str = thing;
} else { } else {
throw new Error("Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer"); throw new Error("Tried to convert a non-string of type " + typeof thing + " to an array buffer");
} }
var res = new ArrayBuffer(str.length); return new dcodeIO.ByteBuffer.wrap(thing, 'binary').toArrayBuffer();
var uint = new Uint8Array(res);
for (var i = 0; i < str.length; i++) {
uint[i] = str.charCodeAt(i);
}
return res;
}, },
isEqual: function(a, b) { isEqual: function(a, b) {
// TODO: Special-case arraybuffers, etc // TODO: Special-case arraybuffers, etc
if (a === undefined || b === undefined) { if (a === undefined || b === undefined) {
return false; return false;
} }
a = stringObject(a); a = util.toString(a);
b = stringObject(b); b = util.toString(b);
var maxLength = Math.max(a.length, b.length); var maxLength = Math.max(a.length, b.length);
if (maxLength < 5) { if (maxLength < 5) {
throw new Error("a/b compare too short"); throw new Error("a/b compare too short");
@ -35683,21 +35595,7 @@ Internal.protoText = function() {
return protoText; return protoText;
}(); }();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
Internal.protobuf = function() { Internal.protobuf = function() {
@ -35705,7 +35603,7 @@ Internal.protobuf = function() {
function loadProtoBufs(filename) { function loadProtoBufs(filename) {
return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure');
}; }
var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto');
@ -35715,44 +35613,50 @@ Internal.protobuf = function() {
}; };
}(); }();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
Internal.BaseKeyType = {
OURS: 1,
THEIRS: 2
};
Internal.ChainType = {
SENDING: 1,
RECEIVING: 2
};
Internal.SessionRecord = function() { Internal.SessionRecord = function() {
'use strict'; 'use strict';
var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7; var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7;
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
var StaticArrayBufferProto = new ArrayBuffer().__proto__;
var StaticUint8ArrayProto = new Uint8Array().__proto__;
function isStringable(thing) {
return (thing === Object(thing) &&
(thing.__proto__ == StaticArrayBufferProto ||
thing.__proto__ == StaticUint8ArrayProto ||
thing.__proto__ == StaticByteBufferProto));
}
function ensureStringed(thing) { function ensureStringed(thing) {
if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") { if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") {
return thing; return thing;
} else if (util.isStringable(thing)) { } else if (isStringable(thing)) {
return util.stringObject(thing); return util.toString(thing);
} else if (thing instanceof Array) { } else if (thing instanceof Array) {
var res = []; var array = [];
for (var i = 0; i < thing.length; i++) { for (var i = 0; i < thing.length; i++) {
res[i] = ensureStringed(thing[i]); array[i] = ensureStringed(thing[i]);
} }
return res; return array;
} else if (thing === Object(thing)) { } else if (thing === Object(thing)) {
var res = {}; var obj = {};
for (var key in thing) { for (var key in thing) {
res[key] = ensureStringed(thing[key]); obj[key] = ensureStringed(thing[key]);
} }
return res; return obj;
} else if (thing === null) { } else if (thing === null) {
return null; return null;
} else { } else {
@ -35804,19 +35708,12 @@ Internal.SessionRecord = function() {
}, },
getSessionByBaseKey: function(baseKey) { getSessionByBaseKey: function(baseKey) {
return this._sessions[util.toString(baseKey)]; var session = this._sessions[util.toString(baseKey)];
}, if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) {
getSessionOrIdentityKeyByBaseKey: function(baseKey) { console.log("Tried to lookup a session using our basekey");
var preferredSession = this.getSessionByBaseKey(baseKey); return undefined;
if (preferredSession !== undefined) {
return preferredSession;
} }
return session;
if (this.identityKey !== undefined) {
return { indexInfo: { remoteIdentityKey: this.identityKey } };
}
throw new Error("Datastore inconsistency: device was stored without identity key");
}, },
getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) { getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) {
this.detectDuplicateOpenSessions(); this.detectDuplicateOpenSessions();
@ -35824,7 +35721,7 @@ Internal.SessionRecord = function() {
var searchKey = util.toString(remoteEphemeralKey); var searchKey = util.toString(remoteEphemeralKey);
var openSession = undefined; var openSession;
for (var key in sessions) { for (var key in sessions) {
if (sessions[key].indexInfo.closed == -1) { if (sessions[key].indexInfo.closed == -1) {
openSession = sessions[key]; openSession = sessions[key];
@ -35855,7 +35752,7 @@ Internal.SessionRecord = function() {
return undefined; return undefined;
}, },
detectDuplicateOpenSessions: function() { detectDuplicateOpenSessions: function() {
var openSession = undefined; var openSession;
var sessions = this._sessions; var sessions = this._sessions;
for (var key in sessions) { for (var key in sessions) {
if (sessions[key].indexInfo.closed == -1) { if (sessions[key].indexInfo.closed == -1) {
@ -35925,8 +35822,8 @@ Internal.SessionRecord = function() {
} }
} }
// Delete current root key and our ephemeral key pair to disallow ratchet stepping // Delete current root key and our ephemeral key pair to disallow ratchet stepping
delete session.currentRatchet['rootKey']; delete session.currentRatchet.rootKey;
delete session.currentRatchet['ephemeralKeyPair']; delete session.currentRatchet.ephemeralKeyPair;
session.indexInfo.closed = Date.now(); session.indexInfo.closed = Date.now();
this.removeOldChains(session); this.removeOldChains(session);
}, },
@ -36185,6 +36082,7 @@ SessionBuilder.prototype = {
// otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key // otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key
if (isInitiator) { if (isInitiator) {
session.indexInfo.baseKey = ourEphemeralKey.pubKey; session.indexInfo.baseKey = ourEphemeralKey.pubKey;
session.indexInfo.baseKeyType = Internal.BaseKeyType.OURS;
return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) { return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) {
session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey; session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey;
return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() { return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() {
@ -36193,6 +36091,7 @@ SessionBuilder.prototype = {
}.bind(this)); }.bind(this));
} else { } else {
session.indexInfo.baseKey = theirEphemeralPubKey; session.indexInfo.baseKey = theirEphemeralPubKey;
session.indexInfo.baseKeyType = Internal.BaseKeyType.THEIRS;
session.currentRatchet.ephemeralKeyPair = ourSignedKey; session.currentRatchet.ephemeralKeyPair = ourSignedKey;
return session; return session;
} }
@ -36211,7 +36110,8 @@ SessionBuilder.prototype = {
}).then(function(masterKey) { }).then(function(masterKey) {
session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = { session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = {
messageKeys : {}, messageKeys : {},
chainKey : { counter : -1, key : masterKey[1] } chainKey : { counter : -1, key : masterKey[1] },
chainType : Internal.ChainType.SENDING
}; };
ratchet.rootKey = masterKey[0]; ratchet.rootKey = masterKey[0];
}); });
@ -36276,6 +36176,9 @@ SessionCipher.prototype = {
session.currentRatchet.ephemeralKeyPair.pubKey session.currentRatchet.ephemeralKeyPair.pubKey
); );
chain = session[util.toString(msg.ephemeralKey)]; chain = session[util.toString(msg.ephemeralKey)];
if (chain.chainType === Internal.ChainType.RECEIVING) {
throw new Error("Tried to encrypt on a receiving chain");
}
return this.fillMessageKeys(chain, chain.chainKey.counter + 1); return this.fillMessageKeys(chain, chain.chainKey.counter + 1);
}.bind(this)).then(function() { }.bind(this)).then(function() {
@ -36334,7 +36237,7 @@ SessionCipher.prototype = {
var messageLengthWithTerminator = messageLength + 1; var messageLengthWithTerminator = messageLength + 1;
var messagePartCount = Math.floor(messageLengthWithTerminator / 160); var messagePartCount = Math.floor(messageLengthWithTerminator / 160);
if (messageLengthWithTerminator % 160 != 0) { if (messageLengthWithTerminator % 160 !== 0) {
messagePartCount++; messagePartCount++;
} }
@ -36422,6 +36325,9 @@ SessionCipher.prototype = {
return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() { return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() {
var chain = session[util.toString(message.ephemeralKey)]; var chain = session[util.toString(message.ephemeralKey)];
if (chain.chainType === Internal.ChainType.SENDING) {
throw new Error("Tried to decrypt on a sending chain");
}
return this.fillMessageKeys(chain, message.counter).then(function() { return this.fillMessageKeys(chain, message.counter).then(function() {
var messageKey = chain.messageKeys[message.counter]; var messageKey = chain.messageKeys[message.counter];
@ -36455,12 +36361,12 @@ SessionCipher.prototype = {
plaintext.set(paddedPlaintext.subarray(0, i)); plaintext.set(paddedPlaintext.subarray(0, i));
plaintext = plaintext.buffer; plaintext = plaintext.buffer;
break; break;
} else if (paddedPlaintext[i] != 0x00) { } else if (paddedPlaintext[i] !== 0x00) {
throw new Error('Invalid padding'); throw new Error('Invalid padding');
} }
} }
delete session['pendingPreKey']; delete session.pendingPreKey;
return plaintext; return plaintext;
}); });
}, },
@ -36541,7 +36447,8 @@ SessionCipher.prototype = {
} }
session[util.toString(ephemeralPublicKey)] = { session[util.toString(ephemeralPublicKey)] = {
messageKeys: {}, messageKeys: {},
chainKey: { counter: -1, key: masterKey[1] } chainKey: { counter: -1, key: masterKey[1] },
chainType: sending ? Internal.ChainType.SENDING : Internal.ChainType.RECEIVING
}; };
ratchet.rootKey = masterKey[0]; ratchet.rootKey = masterKey[0];
}); });

View file

@ -25133,21 +25133,7 @@ run();
/* vim: ts=4:sw=4:expandtab /* vim: ts=4:sw=4:expandtab */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
(function() { (function() {
@ -25173,7 +25159,7 @@ var Internal = Internal || {};
var priv = new Uint8Array(privKey); var priv = new Uint8Array(privKey);
priv[0] &= 248; priv[0] &= 248;
priv[31] &= 127; priv[31] &= 127;
priv[31] |= 64 priv[31] |= 64;
// Where to store the result // Where to store the result
var publicKey_ptr = Module._malloc(32); var publicKey_ptr = Module._malloc(32);
@ -35191,7 +35177,7 @@ Curve25519Worker.prototype = {
return curve25519.verify(pubKey, msg, sig); return curve25519.verify(pubKey, msg, sig);
} }
}; };
}; }
Internal.Curve = wrapCurve25519(Internal.curve25519); Internal.Curve = wrapCurve25519(Internal.curve25519);
Internal.Curve.async = wrapCurve25519(Internal.curve25519_async); Internal.Curve.async = wrapCurve25519(Internal.curve25519_async);
@ -35222,21 +35208,8 @@ Curve25519Worker.prototype = {
})(); })();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
(function() { (function() {
@ -35363,63 +35336,21 @@ var Internal = Internal || {};
})(); })();
/* vim: ts=4:sw=4 /*
* * vim: ts=4:sw=4
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
var util = (function() { var util = (function() {
'use strict'; 'use strict';
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
var StaticArrayBufferProto = new ArrayBuffer().__proto__; var StaticArrayBufferProto = new ArrayBuffer().__proto__;
var StaticUint8ArrayProto = new Uint8Array().__proto__;
function stringObject(thing) {
if (typeof thing === 'string') {
return thing;
}
if (thing === Object(thing)) {
if (thing.__proto__ == StaticUint8ArrayProto) {
return String.fromCharCode.apply(null, thing);
}
if (thing.__proto__ == StaticArrayBufferProto) {
return stringObject(new Uint8Array(thing));
}
if (thing.__proto__ == StaticByteBufferProto) {
return thing.toString('binary');
}
}
throw new Error('unsure how to stringify object of type ' + typeof thing);
}
return { return {
toString: function(thing) { toString: function(thing) {
if (typeof thing == 'string') { if (typeof thing == 'string') {
return thing; return thing;
} else if (util.isStringable(thing)) {
return util.stringObject(thing);
} else {
throw new Error("Unsure how to convert object to string from type " + typeof thing);
} }
}, return new dcodeIO.ByteBuffer.wrap(thing).toString('binary');
stringObject: stringObject,
isStringable: function (thing) {
return (thing === Object(thing) &&
(thing.__proto__ == StaticArrayBufferProto ||
thing.__proto__ == StaticUint8ArrayProto ||
thing.__proto__ == StaticByteBufferProto));
}, },
toArrayBuffer: function(thing) { toArrayBuffer: function(thing) {
if (thing === undefined) { if (thing === undefined) {
@ -35429,42 +35360,23 @@ var util = (function() {
if (thing.__proto__ == StaticArrayBufferProto) { if (thing.__proto__ == StaticArrayBufferProto) {
return thing; return thing;
} }
//TODO: Several more cases here...
}
if (thing instanceof Array) {
// Assuming Uint16Array from curve25519
//TODO: Move to convertToArrayBuffer
var res = new ArrayBuffer(thing.length * 2);
var uint = new Uint16Array(res);
for (var i = 0; i < thing.length; i++) {
uint[i] = thing[i];
}
return res;
} }
var str; var str;
if (util.isStringable(thing)) { if (typeof thing == "string") {
str = util.stringObject(thing);
} else if (typeof thing == "string") {
str = thing; str = thing;
} else { } else {
throw new Error("Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer"); throw new Error("Tried to convert a non-string of type " + typeof thing + " to an array buffer");
} }
var res = new ArrayBuffer(str.length); return new dcodeIO.ByteBuffer.wrap(thing, 'binary').toArrayBuffer();
var uint = new Uint8Array(res);
for (var i = 0; i < str.length; i++) {
uint[i] = str.charCodeAt(i);
}
return res;
}, },
isEqual: function(a, b) { isEqual: function(a, b) {
// TODO: Special-case arraybuffers, etc // TODO: Special-case arraybuffers, etc
if (a === undefined || b === undefined) { if (a === undefined || b === undefined) {
return false; return false;
} }
a = stringObject(a); a = util.toString(a);
b = stringObject(b); b = util.toString(b);
var maxLength = Math.max(a.length, b.length); var maxLength = Math.max(a.length, b.length);
if (maxLength < 5) { if (maxLength < 5) {
throw new Error("a/b compare too short"); throw new Error("a/b compare too short");
@ -35559,21 +35471,7 @@ Internal.protoText = function() {
return protoText; return protoText;
}(); }();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
Internal.protobuf = function() { Internal.protobuf = function() {
@ -35581,7 +35479,7 @@ Internal.protobuf = function() {
function loadProtoBufs(filename) { function loadProtoBufs(filename) {
return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure'); return dcodeIO.ProtoBuf.loadProto(Internal.protoText['protos/' + filename]).build('textsecure');
}; }
var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto'); var protocolMessages = loadProtoBufs('WhisperTextProtocol.proto');
@ -35591,44 +35489,50 @@ Internal.protobuf = function() {
}; };
}(); }();
/* vim: ts=4:sw=4 /* vim: ts=4:sw=4 */
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Internal = Internal || {}; var Internal = Internal || {};
Internal.BaseKeyType = {
OURS: 1,
THEIRS: 2
};
Internal.ChainType = {
SENDING: 1,
RECEIVING: 2
};
Internal.SessionRecord = function() { Internal.SessionRecord = function() {
'use strict'; 'use strict';
var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7; var MESSAGE_LOST_THRESHOLD_MS = 1000*60*60*24*7;
var StaticByteBufferProto = new dcodeIO.ByteBuffer().__proto__;
var StaticArrayBufferProto = new ArrayBuffer().__proto__;
var StaticUint8ArrayProto = new Uint8Array().__proto__;
function isStringable(thing) {
return (thing === Object(thing) &&
(thing.__proto__ == StaticArrayBufferProto ||
thing.__proto__ == StaticUint8ArrayProto ||
thing.__proto__ == StaticByteBufferProto));
}
function ensureStringed(thing) { function ensureStringed(thing) {
if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") { if (typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean") {
return thing; return thing;
} else if (util.isStringable(thing)) { } else if (isStringable(thing)) {
return util.stringObject(thing); return util.toString(thing);
} else if (thing instanceof Array) { } else if (thing instanceof Array) {
var res = []; var array = [];
for (var i = 0; i < thing.length; i++) { for (var i = 0; i < thing.length; i++) {
res[i] = ensureStringed(thing[i]); array[i] = ensureStringed(thing[i]);
} }
return res; return array;
} else if (thing === Object(thing)) { } else if (thing === Object(thing)) {
var res = {}; var obj = {};
for (var key in thing) { for (var key in thing) {
res[key] = ensureStringed(thing[key]); obj[key] = ensureStringed(thing[key]);
} }
return res; return obj;
} else if (thing === null) { } else if (thing === null) {
return null; return null;
} else { } else {
@ -35680,19 +35584,12 @@ Internal.SessionRecord = function() {
}, },
getSessionByBaseKey: function(baseKey) { getSessionByBaseKey: function(baseKey) {
return this._sessions[util.toString(baseKey)]; var session = this._sessions[util.toString(baseKey)];
}, if (session && session.indexInfo.baseKeyType === Internal.BaseKeyType.OURS) {
getSessionOrIdentityKeyByBaseKey: function(baseKey) { console.log("Tried to lookup a session using our basekey");
var preferredSession = this.getSessionByBaseKey(baseKey); return undefined;
if (preferredSession !== undefined) {
return preferredSession;
} }
return session;
if (this.identityKey !== undefined) {
return { indexInfo: { remoteIdentityKey: this.identityKey } };
}
throw new Error("Datastore inconsistency: device was stored without identity key");
}, },
getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) { getSessionByRemoteEphemeralKey: function(remoteEphemeralKey) {
this.detectDuplicateOpenSessions(); this.detectDuplicateOpenSessions();
@ -35700,7 +35597,7 @@ Internal.SessionRecord = function() {
var searchKey = util.toString(remoteEphemeralKey); var searchKey = util.toString(remoteEphemeralKey);
var openSession = undefined; var openSession;
for (var key in sessions) { for (var key in sessions) {
if (sessions[key].indexInfo.closed == -1) { if (sessions[key].indexInfo.closed == -1) {
openSession = sessions[key]; openSession = sessions[key];
@ -35731,7 +35628,7 @@ Internal.SessionRecord = function() {
return undefined; return undefined;
}, },
detectDuplicateOpenSessions: function() { detectDuplicateOpenSessions: function() {
var openSession = undefined; var openSession;
var sessions = this._sessions; var sessions = this._sessions;
for (var key in sessions) { for (var key in sessions) {
if (sessions[key].indexInfo.closed == -1) { if (sessions[key].indexInfo.closed == -1) {
@ -35801,8 +35698,8 @@ Internal.SessionRecord = function() {
} }
} }
// Delete current root key and our ephemeral key pair to disallow ratchet stepping // Delete current root key and our ephemeral key pair to disallow ratchet stepping
delete session.currentRatchet['rootKey']; delete session.currentRatchet.rootKey;
delete session.currentRatchet['ephemeralKeyPair']; delete session.currentRatchet.ephemeralKeyPair;
session.indexInfo.closed = Date.now(); session.indexInfo.closed = Date.now();
this.removeOldChains(session); this.removeOldChains(session);
}, },
@ -36061,6 +35958,7 @@ SessionBuilder.prototype = {
// otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key // otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key
if (isInitiator) { if (isInitiator) {
session.indexInfo.baseKey = ourEphemeralKey.pubKey; session.indexInfo.baseKey = ourEphemeralKey.pubKey;
session.indexInfo.baseKeyType = Internal.BaseKeyType.OURS;
return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) { return Internal.crypto.createKeyPair().then(function(ourSendingEphemeralKey) {
session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey; session.currentRatchet.ephemeralKeyPair = ourSendingEphemeralKey;
return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() { return this.calculateSendingRatchet(session, theirSignedPubKey).then(function() {
@ -36069,6 +35967,7 @@ SessionBuilder.prototype = {
}.bind(this)); }.bind(this));
} else { } else {
session.indexInfo.baseKey = theirEphemeralPubKey; session.indexInfo.baseKey = theirEphemeralPubKey;
session.indexInfo.baseKeyType = Internal.BaseKeyType.THEIRS;
session.currentRatchet.ephemeralKeyPair = ourSignedKey; session.currentRatchet.ephemeralKeyPair = ourSignedKey;
return session; return session;
} }
@ -36087,7 +35986,8 @@ SessionBuilder.prototype = {
}).then(function(masterKey) { }).then(function(masterKey) {
session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = { session[util.toString(ratchet.ephemeralKeyPair.pubKey)] = {
messageKeys : {}, messageKeys : {},
chainKey : { counter : -1, key : masterKey[1] } chainKey : { counter : -1, key : masterKey[1] },
chainType : Internal.ChainType.SENDING
}; };
ratchet.rootKey = masterKey[0]; ratchet.rootKey = masterKey[0];
}); });
@ -36152,6 +36052,9 @@ SessionCipher.prototype = {
session.currentRatchet.ephemeralKeyPair.pubKey session.currentRatchet.ephemeralKeyPair.pubKey
); );
chain = session[util.toString(msg.ephemeralKey)]; chain = session[util.toString(msg.ephemeralKey)];
if (chain.chainType === Internal.ChainType.RECEIVING) {
throw new Error("Tried to encrypt on a receiving chain");
}
return this.fillMessageKeys(chain, chain.chainKey.counter + 1); return this.fillMessageKeys(chain, chain.chainKey.counter + 1);
}.bind(this)).then(function() { }.bind(this)).then(function() {
@ -36210,7 +36113,7 @@ SessionCipher.prototype = {
var messageLengthWithTerminator = messageLength + 1; var messageLengthWithTerminator = messageLength + 1;
var messagePartCount = Math.floor(messageLengthWithTerminator / 160); var messagePartCount = Math.floor(messageLengthWithTerminator / 160);
if (messageLengthWithTerminator % 160 != 0) { if (messageLengthWithTerminator % 160 !== 0) {
messagePartCount++; messagePartCount++;
} }
@ -36298,6 +36201,9 @@ SessionCipher.prototype = {
return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() { return this.maybeStepRatchet(session, remoteEphemeralKey, message.previousCounter).then(function() {
var chain = session[util.toString(message.ephemeralKey)]; var chain = session[util.toString(message.ephemeralKey)];
if (chain.chainType === Internal.ChainType.SENDING) {
throw new Error("Tried to decrypt on a sending chain");
}
return this.fillMessageKeys(chain, message.counter).then(function() { return this.fillMessageKeys(chain, message.counter).then(function() {
var messageKey = chain.messageKeys[message.counter]; var messageKey = chain.messageKeys[message.counter];
@ -36331,12 +36237,12 @@ SessionCipher.prototype = {
plaintext.set(paddedPlaintext.subarray(0, i)); plaintext.set(paddedPlaintext.subarray(0, i));
plaintext = plaintext.buffer; plaintext = plaintext.buffer;
break; break;
} else if (paddedPlaintext[i] != 0x00) { } else if (paddedPlaintext[i] !== 0x00) {
throw new Error('Invalid padding'); throw new Error('Invalid padding');
} }
} }
delete session['pendingPreKey']; delete session.pendingPreKey;
return plaintext; return plaintext;
}); });
}, },
@ -36417,7 +36323,8 @@ SessionCipher.prototype = {
} }
session[util.toString(ephemeralPublicKey)] = { session[util.toString(ephemeralPublicKey)] = {
messageKeys: {}, messageKeys: {},
chainKey: { counter: -1, key: masterKey[1] } chainKey: { counter: -1, key: masterKey[1] },
chainType: sending ? Internal.ChainType.SENDING : Internal.ChainType.RECEIVING
}; };
ratchet.rootKey = masterKey[0]; ratchet.rootKey = masterKey[0];
}); });