From 9f4fcc5afa7a8a0997e5495eacb1b4fbcc49e9cf Mon Sep 17 00:00:00 2001 From: lilia Date: Thu, 22 Jun 2017 15:24:01 -0700 Subject: [PATCH] Send null messages to mask verified syncs First construct a null message of random size and contents and send it to the destination. Then include that same padding in the verification sync. Note that the sync message is additionally randomly padded like all other sync messages. This lets Verified sync messages appear the same as normal sync message traffic. // FREEBIE --- js/libtextsecure.js | 32 ++++++++++++++++++++++++-------- libtextsecure/sendmessage.js | 32 ++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 5a4aff8ca..efbe1a256 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -39290,18 +39290,34 @@ MessageSender.prototype = { var myNumber = textsecure.storage.user.getNumber(); var myDevice = textsecure.storage.user.getDeviceId(); if (myDevice != 1) { - var verified = new textsecure.protobuf.Verified(); - verified.state = state; - verified.destination = destination; - verified.identityKey = identityKey; + // First send a null message to mask the sync message. + var nullMessage = new textsecure.protobuf.NullMessage(); - var syncMessage = this.createSyncMessage(); - syncMessage.verified = verified; + // Generate a random int from 1 and 512 + var buffer = libsignal.crypto.getRandomBytes(1); + var paddingLength = (new Uint8Array(buffer)[0] & 0x1ff) + 1; + + // Generate a random padding buffer of the chosen size + nullMessage.padding = libsignal.crypto.getRandomBytes(paddingLength); var contentMessage = new textsecure.protobuf.Content(); - contentMessage.syncMessage = syncMessage; + contentMessage.nullMessage = nullMessage; - return this.sendIndividualProto(myNumber, contentMessage, Date.now()); + return this.sendIndividualProto(destination, contentMessage, Date.now()).then(function() { + var verified = new textsecure.protobuf.Verified(); + verified.state = state; + verified.destination = destination; + verified.identityKey = identityKey; + verified.nullMessage = nullMessage.padding; + + var syncMessage = this.createSyncMessage(); + syncMessage.verified = verified; + + var contentMessage = new textsecure.protobuf.Content(); + contentMessage.syncMessage = syncMessage; + + return this.sendIndividualProto(myNumber, contentMessage, Date.now()); + }.bind(this)); } }, diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 2dd11a80c..46d187d50 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -322,18 +322,34 @@ MessageSender.prototype = { var myNumber = textsecure.storage.user.getNumber(); var myDevice = textsecure.storage.user.getDeviceId(); if (myDevice != 1) { - var verified = new textsecure.protobuf.Verified(); - verified.state = state; - verified.destination = destination; - verified.identityKey = identityKey; + // First send a null message to mask the sync message. + var nullMessage = new textsecure.protobuf.NullMessage(); - var syncMessage = this.createSyncMessage(); - syncMessage.verified = verified; + // Generate a random int from 1 and 512 + var buffer = libsignal.crypto.getRandomBytes(1); + var paddingLength = (new Uint8Array(buffer)[0] & 0x1ff) + 1; + + // Generate a random padding buffer of the chosen size + nullMessage.padding = libsignal.crypto.getRandomBytes(paddingLength); var contentMessage = new textsecure.protobuf.Content(); - contentMessage.syncMessage = syncMessage; + contentMessage.nullMessage = nullMessage; - return this.sendIndividualProto(myNumber, contentMessage, Date.now()); + return this.sendIndividualProto(destination, contentMessage, Date.now()).then(function() { + var verified = new textsecure.protobuf.Verified(); + verified.state = state; + verified.destination = destination; + verified.identityKey = identityKey; + verified.nullMessage = nullMessage.padding; + + var syncMessage = this.createSyncMessage(); + syncMessage.verified = verified; + + var contentMessage = new textsecure.protobuf.Content(); + contentMessage.syncMessage = syncMessage; + + return this.sendIndividualProto(myNumber, contentMessage, Date.now()); + }.bind(this)); } },