Skip to content

Commit

Permalink
Add padding for push messages.
Browse files Browse the repository at this point in the history
1) Use 'bit padding.'

1) By default, pad at 160 byte increments.
  • Loading branch information
moxie0 committed Oct 20, 2014
1 parent fcaa3f0 commit 07fd17c
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ private byte[] decrypt(SessionState sessionState, byte[] decodedMessage)
}

WhisperMessage ciphertextMessage = new WhisperMessage(decodedMessage);

if (ciphertextMessage.getMessageVersion() != sessionState.getSessionVersion()) {
throw new InvalidMessageException(String.format("Message version %d, but session version %d",
ciphertextMessage.getMessageVersion(),
sessionState.getSessionVersion()));
}

ECPublicKey theirEphemeral = ciphertextMessage.getSenderEphemeral();
int counter = ciphertextMessage.getCounter();
ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,53 @@
*/
package org.whispersystems.textsecure.push;

import android.util.Log;

import org.whispersystems.textsecure.crypto.TransportDetails;
import org.whispersystems.textsecure.util.Base64;

import java.io.IOException;

public class PushTransportDetails implements TransportDetails {

private final int messageVersion;

public PushTransportDetails(int messageVersion) {
this.messageVersion = messageVersion;
}

@Override
public byte[] getStrippedPaddingMessageBody(byte[] messageWithPadding) {
return messageWithPadding;
if (messageVersion < 2) throw new AssertionError("Unknown version: " + messageVersion);
else if (messageVersion == 2) return messageWithPadding;

int paddingStart = 0;

for (int i=messageWithPadding.length-1;i>=0;i--) {
if (messageWithPadding[i] == (byte)0x80) {
paddingStart = i;
break;
} else if (messageWithPadding[i] != (byte)0x00) {
Log.w("PushTransportDetails", "Padding byte is malformed, returning unstripped padding.");
return messageWithPadding;
}
}

byte[] strippedMessage = new byte[messageWithPadding.length - paddingStart];
System.arraycopy(messageWithPadding, 0, strippedMessage, 0, strippedMessage.length);

return strippedMessage;
}

@Override
public byte[] getPaddedMessageBody(byte[] messageBody) {
return messageBody;
if (messageVersion < 2) throw new AssertionError("Unknown version: " + messageVersion);
else if (messageVersion == 2) return messageBody;

byte[] paddedMessage = new byte[getPaddedMessageLength(messageBody.length)];
System.arraycopy(messageBody, 0, paddedMessage, 0, messageBody.length);
paddedMessage[messageBody.length] = (byte)0x80;

return paddedMessage;
}

@Override
Expand All @@ -41,4 +74,15 @@ public byte[] getEncodedMessage(byte[] messageWithMac) {
public byte[] getDecodedMessage(byte[] encodedMessageBytes) throws IOException {
return encodedMessageBytes;
}

private int getPaddedMessageLength(int messageLength) {
int messageLengthWithTerminator = messageLength + 1;
int messagePartCount = messageLengthWithTerminator / 160;

if (messageLengthWithTerminator % 160 != 0) {
messagePartCount++;
}

return messagePartCount * 160;
}
}
11 changes: 11 additions & 0 deletions library/src/org/whispersystems/textsecure/storage/SessionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

public class SessionUtil {

public static int getSessionVersion(Context context,
MasterSecret masterSecret,
RecipientDevice recipient)
{
return
new TextSecureSessionStore(context, masterSecret)
.loadSession(recipient.getRecipientId(), recipient.getDeviceId())
.getSessionState()
.getSessionVersion();
}

public static boolean hasEncryptCapableSession(Context context,
MasterSecret masterSecret,
CanonicalRecipient recipient)
Expand Down
11 changes: 8 additions & 3 deletions src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@
import org.whispersystems.libaxolotl.state.SessionStore;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
import org.whispersystems.textsecure.crypto.TransportDetails;
import org.whispersystems.textsecure.push.IncomingPushMessage;
import org.whispersystems.textsecure.push.PushTransportDetails;
import org.whispersystems.textsecure.storage.RecipientDevice;
import org.whispersystems.textsecure.storage.SessionUtil;
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Hex;
Expand Down Expand Up @@ -210,10 +213,12 @@ public void run() {
return;
}

SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
byte[] plaintextBody = sessionCipher.decrypt(message.getBody());
int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, recipientDevice);
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
byte[] plaintextBody = sessionCipher.decrypt(message.getBody());
TransportDetails transport = new PushTransportDetails(sessionVersion);

message = message.withBody(plaintextBody);
message = message.withBody(transport.getStrippedPaddingMessageBody(plaintextBody));
sendResult(PushReceiver.RESULT_OK);
} catch (InvalidMessageException | LegacyMessageException | RecipientFormattingException e) {
Log.w("DecryptionQueue", e);
Expand Down
5 changes: 4 additions & 1 deletion src/org/thoughtcrime/securesms/transport/PushTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.whispersystems.textsecure.push.PushBody;
import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent;
import org.whispersystems.textsecure.push.PushServiceSocket;
import org.whispersystems.textsecure.push.PushTransportDetails;
import org.whispersystems.textsecure.push.StaleDevices;
import org.whispersystems.textsecure.push.StaleDevicesException;
import org.whispersystems.textsecure.push.UnregisteredUserException;
Expand Down Expand Up @@ -344,8 +345,10 @@ private PushBody getEncryptedMessage(PushServiceSocket socket, long threadId,
}
}

int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, pushAddress);
SessionCipher cipher = SessionCipherFactory.getInstance(context, masterSecret, pushAddress);
CiphertextMessage message = cipher.encrypt(plaintext);
byte[] paddedPlaintext = new PushTransportDetails(sessionVersion).getPaddedMessageBody(plaintext);
CiphertextMessage message = cipher.encrypt(paddedPlaintext);
int remoteRegistrationId = cipher.getRemoteRegistrationId();

if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
Expand Down

0 comments on commit 07fd17c

Please sign in to comment.