From f2162622984bb1b93ae86f78c71705d6c06d659a Mon Sep 17 00:00:00 2001 From: lilia Date: Wed, 18 May 2016 11:36:30 -0700 Subject: [PATCH] Update libsignal-protocol v0.12.0 Moves version byte check to protocol lib. // FREEBIE --- js/libtextsecure.js | 46 ++++++++++++++--------------- libtextsecure/libsignal-protocol.js | 33 +++++++++++++-------- libtextsecure/message_receiver.js | 13 ++------ 3 files changed, 44 insertions(+), 48 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 9f47463db..e6e906e4c 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -36174,10 +36174,11 @@ SessionCipher.prototype = { return Internal.SessionRecord.deserialize(serialized); }); }, - encrypt: function(plaintext) { + encrypt: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer(); return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { - if (!(plaintext instanceof ArrayBuffer)) { - throw new Error("Expected plaintext to be an ArrayBuffer"); + if (!(buffer instanceof ArrayBuffer)) { + throw new Error("Expected buffer to be an ArrayBuffer"); } var address = this.remoteAddress.toString(); @@ -36185,10 +36186,10 @@ SessionCipher.prototype = { var msg = new Internal.protobuf.WhisperMessage(); var paddedPlaintext = new Uint8Array( - this.getPaddedMessageLength(plaintext.byteLength + 1) - 1 + this.getPaddedMessageLength(buffer.byteLength + 1) - 1 ); - paddedPlaintext.set(new Uint8Array(plaintext)); - paddedPlaintext[plaintext.byteLength] = 0x80; + paddedPlaintext.set(new Uint8Array(buffer)); + paddedPlaintext[buffer.byteLength] = 0x80; return Promise.all([ this.storage.getIdentityKeyPair(), @@ -36274,18 +36275,19 @@ SessionCipher.prototype = { return messagePartCount * 160; }, - decryptWhisperMessage: function(messageBytes) { + decryptWhisperMessage: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer(); return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { var address = this.remoteAddress.toString(); return this.getRecord(address).then(function(record) { if (!record) { throw new Error("No record for device " + address); } - var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8); + var messageProto = buffer.slice(1, buffer.byteLength - 8); var message = Internal.protobuf.WhisperMessage.decode(messageProto); var remoteEphemeralKey = message.ephemeralKey.toArrayBuffer(); var session = record.getSessionByRemoteEphemeralKey(remoteEphemeralKey); - return this.doDecryptWhisperMessage(util.toArrayBuffer(messageBytes), session).then(function(plaintext) { + return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) { record.updateSessionState(session); return this.storage.storeSession(address, record.serialize()).then(function() { return plaintext; @@ -36294,11 +36296,16 @@ SessionCipher.prototype = { }.bind(this)); }.bind(this)); }, - decryptPreKeyWhisperMessage: function(encodedMessage, encoding) { + decryptPreKeyWhisperMessage: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding); + var version = buffer.readUint8(); + if ((version & 0xF) > 3 || (version >> 4) < 3) { // min version > 3 or max version < 3 + throw new Error("Incompatible version number on PreKeyWhisperMessage"); + } return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { var address = this.remoteAddress.toString(); return this.getRecord(address).then(function(record) { - var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(encodedMessage, encoding); + var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(buffer); if (!record) { if (preKeyProto.registrationId === undefined) { throw new Error("No registrationId"); @@ -36332,8 +36339,8 @@ SessionCipher.prototype = { throw new Error("Expected messageBytes to be an ArrayBuffer"); } var version = (new Uint8Array(messageBytes))[0]; - if (version !== ((3 << 4) | 3)) { - throw new Error("Bad version number on WhisperMessage"); + if ((version & 0xF) > 3 || (version >> 4) < 3) { // min version > 3 or max version < 3 + throw new Error("Incompatible version number on WhisperMessage"); } var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8); var mac = messageBytes.slice(messageBytes.byteLength - 8, messageBytes.byteLength); @@ -38082,7 +38089,7 @@ MessageReceiver.prototype.extend({ var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address); switch(envelope.type) { case textsecure.protobuf.Envelope.Type.CIPHERTEXT: - promise = sessionCipher.decryptWhisperMessage(ciphertext.toArrayBuffer()); + promise = sessionCipher.decryptWhisperMessage(ciphertext); break; case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE: console.log('prekey whisper message'); @@ -38100,16 +38107,8 @@ MessageReceiver.prototype.extend({ }.bind(this)); }, decryptPreKeyWhisperMessage: function(ciphertext, sessionCipher, address) { - ciphertext.mark(); - var version = ciphertext.readUint8(); - if ((version & 0xF) > 3 || (version >> 4) < 3) { - // min version > 3 or max version < 3 - throw new Error("Incompatible version byte"); - } return sessionCipher.decryptPreKeyWhisperMessage(ciphertext).catch(function(e) { if (e.message === 'Unknown identity key') { - ciphertext.reset(); // restore the version byte. - // create an error that the UI will pick up and ask the // user if they want to re-negotiate throw new textsecure.IncomingIdentityKeyError( @@ -38292,8 +38291,7 @@ MessageReceiver.prototype.extend({ then(decryptAttachment). then(updateAttachment); }, - tryMessageAgain: function(from, encodedMessage) { - var ciphertext = dcodeIO.ByteBuffer.wrap(encodedMessage); + tryMessageAgain: function(from, ciphertext) { var address = libsignal.SignalProtocolAddress.fromString(from); var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address); console.log('retrying prekey whisper message'); diff --git a/libtextsecure/libsignal-protocol.js b/libtextsecure/libsignal-protocol.js index eaca408e0..980c62971 100644 --- a/libtextsecure/libsignal-protocol.js +++ b/libtextsecure/libsignal-protocol.js @@ -36060,10 +36060,11 @@ SessionCipher.prototype = { return Internal.SessionRecord.deserialize(serialized); }); }, - encrypt: function(plaintext) { + encrypt: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer(); return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { - if (!(plaintext instanceof ArrayBuffer)) { - throw new Error("Expected plaintext to be an ArrayBuffer"); + if (!(buffer instanceof ArrayBuffer)) { + throw new Error("Expected buffer to be an ArrayBuffer"); } var address = this.remoteAddress.toString(); @@ -36071,10 +36072,10 @@ SessionCipher.prototype = { var msg = new Internal.protobuf.WhisperMessage(); var paddedPlaintext = new Uint8Array( - this.getPaddedMessageLength(plaintext.byteLength + 1) - 1 + this.getPaddedMessageLength(buffer.byteLength + 1) - 1 ); - paddedPlaintext.set(new Uint8Array(plaintext)); - paddedPlaintext[plaintext.byteLength] = 0x80; + paddedPlaintext.set(new Uint8Array(buffer)); + paddedPlaintext[buffer.byteLength] = 0x80; return Promise.all([ this.storage.getIdentityKeyPair(), @@ -36160,18 +36161,19 @@ SessionCipher.prototype = { return messagePartCount * 160; }, - decryptWhisperMessage: function(messageBytes) { + decryptWhisperMessage: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer(); return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { var address = this.remoteAddress.toString(); return this.getRecord(address).then(function(record) { if (!record) { throw new Error("No record for device " + address); } - var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8); + var messageProto = buffer.slice(1, buffer.byteLength - 8); var message = Internal.protobuf.WhisperMessage.decode(messageProto); var remoteEphemeralKey = message.ephemeralKey.toArrayBuffer(); var session = record.getSessionByRemoteEphemeralKey(remoteEphemeralKey); - return this.doDecryptWhisperMessage(util.toArrayBuffer(messageBytes), session).then(function(plaintext) { + return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) { record.updateSessionState(session); return this.storage.storeSession(address, record.serialize()).then(function() { return plaintext; @@ -36180,11 +36182,16 @@ SessionCipher.prototype = { }.bind(this)); }.bind(this)); }, - decryptPreKeyWhisperMessage: function(encodedMessage, encoding) { + decryptPreKeyWhisperMessage: function(buffer, encoding) { + buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding); + var version = buffer.readUint8(); + if ((version & 0xF) > 3 || (version >> 4) < 3) { // min version > 3 or max version < 3 + throw new Error("Incompatible version number on PreKeyWhisperMessage"); + } return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() { var address = this.remoteAddress.toString(); return this.getRecord(address).then(function(record) { - var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(encodedMessage, encoding); + var preKeyProto = Internal.protobuf.PreKeyWhisperMessage.decode(buffer); if (!record) { if (preKeyProto.registrationId === undefined) { throw new Error("No registrationId"); @@ -36218,8 +36225,8 @@ SessionCipher.prototype = { throw new Error("Expected messageBytes to be an ArrayBuffer"); } var version = (new Uint8Array(messageBytes))[0]; - if (version !== ((3 << 4) | 3)) { - throw new Error("Bad version number on WhisperMessage"); + if ((version & 0xF) > 3 || (version >> 4) < 3) { // min version > 3 or max version < 3 + throw new Error("Incompatible version number on WhisperMessage"); } var messageProto = messageBytes.slice(1, messageBytes.byteLength- 8); var mac = messageBytes.slice(messageBytes.byteLength - 8, messageBytes.byteLength); diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 90ef0548c..2fcfc9b4e 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -114,7 +114,7 @@ MessageReceiver.prototype.extend({ var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address); switch(envelope.type) { case textsecure.protobuf.Envelope.Type.CIPHERTEXT: - promise = sessionCipher.decryptWhisperMessage(ciphertext.toArrayBuffer()); + promise = sessionCipher.decryptWhisperMessage(ciphertext); break; case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE: console.log('prekey whisper message'); @@ -132,16 +132,8 @@ MessageReceiver.prototype.extend({ }.bind(this)); }, decryptPreKeyWhisperMessage: function(ciphertext, sessionCipher, address) { - ciphertext.mark(); - var version = ciphertext.readUint8(); - if ((version & 0xF) > 3 || (version >> 4) < 3) { - // min version > 3 or max version < 3 - throw new Error("Incompatible version byte"); - } return sessionCipher.decryptPreKeyWhisperMessage(ciphertext).catch(function(e) { if (e.message === 'Unknown identity key') { - ciphertext.reset(); // restore the version byte. - // create an error that the UI will pick up and ask the // user if they want to re-negotiate throw new textsecure.IncomingIdentityKeyError( @@ -324,8 +316,7 @@ MessageReceiver.prototype.extend({ then(decryptAttachment). then(updateAttachment); }, - tryMessageAgain: function(from, encodedMessage) { - var ciphertext = dcodeIO.ByteBuffer.wrap(encodedMessage); + tryMessageAgain: function(from, ciphertext) { var address = libsignal.SignalProtocolAddress.fromString(from); var sessionCipher = new libsignal.SessionCipher(textsecure.storage.protocol, address); console.log('retrying prekey whisper message');