mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-25 09:57:20 +00:00
Add padding for push messages.
1) Use 'bit padding.' 1) By default, pad at 160 byte increments.
This commit is contained in:
parent
fcaa3f0d73
commit
07fd17ccda
@ -168,6 +168,13 @@ public class SessionCipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WhisperMessage ciphertextMessage = new WhisperMessage(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();
|
ECPublicKey theirEphemeral = ciphertextMessage.getSenderEphemeral();
|
||||||
int counter = ciphertextMessage.getCounter();
|
int counter = ciphertextMessage.getCounter();
|
||||||
ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral);
|
ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral);
|
||||||
|
@ -16,20 +16,53 @@
|
|||||||
*/
|
*/
|
||||||
package org.whispersystems.textsecure.push;
|
package org.whispersystems.textsecure.push;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.whispersystems.textsecure.crypto.TransportDetails;
|
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||||
import org.whispersystems.textsecure.util.Base64;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class PushTransportDetails implements TransportDetails {
|
public class PushTransportDetails implements TransportDetails {
|
||||||
|
|
||||||
|
private final int messageVersion;
|
||||||
|
|
||||||
|
public PushTransportDetails(int messageVersion) {
|
||||||
|
this.messageVersion = messageVersion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getStrippedPaddingMessageBody(byte[] messageWithPadding) {
|
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
|
@Override
|
||||||
public byte[] getPaddedMessageBody(byte[] messageBody) {
|
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
|
@Override
|
||||||
@ -41,4 +74,15 @@ public class PushTransportDetails implements TransportDetails {
|
|||||||
public byte[] getDecodedMessage(byte[] encodedMessageBytes) throws IOException {
|
public byte[] getDecodedMessage(byte[] encodedMessageBytes) throws IOException {
|
||||||
return encodedMessageBytes;
|
return encodedMessageBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getPaddedMessageLength(int messageLength) {
|
||||||
|
int messageLengthWithTerminator = messageLength + 1;
|
||||||
|
int messagePartCount = messageLengthWithTerminator / 160;
|
||||||
|
|
||||||
|
if (messageLengthWithTerminator % 160 != 0) {
|
||||||
|
messagePartCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return messagePartCount * 160;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,17 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
|
|||||||
|
|
||||||
public class SessionUtil {
|
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,
|
public static boolean hasEncryptCapableSession(Context context,
|
||||||
MasterSecret masterSecret,
|
MasterSecret masterSecret,
|
||||||
CanonicalRecipient recipient)
|
CanonicalRecipient recipient)
|
||||||
|
@ -52,8 +52,11 @@ import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
|||||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
import org.whispersystems.libaxolotl.state.SessionStore;
|
||||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||||
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
||||||
|
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||||
|
import org.whispersystems.textsecure.push.PushTransportDetails;
|
||||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||||
|
import org.whispersystems.textsecure.storage.SessionUtil;
|
||||||
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
|
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
|
||||||
import org.whispersystems.textsecure.util.Base64;
|
import org.whispersystems.textsecure.util.Base64;
|
||||||
import org.whispersystems.textsecure.util.Hex;
|
import org.whispersystems.textsecure.util.Hex;
|
||||||
@ -210,10 +213,12 @@ public class DecryptingQueue {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, recipientDevice);
|
||||||
byte[] plaintextBody = sessionCipher.decrypt(message.getBody());
|
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);
|
sendResult(PushReceiver.RESULT_OK);
|
||||||
} catch (InvalidMessageException | LegacyMessageException | RecipientFormattingException e) {
|
} catch (InvalidMessageException | LegacyMessageException | RecipientFormattingException e) {
|
||||||
Log.w("DecryptionQueue", e);
|
Log.w("DecryptionQueue", e);
|
||||||
|
@ -52,6 +52,7 @@ import org.whispersystems.textsecure.push.PushAttachmentPointer;
|
|||||||
import org.whispersystems.textsecure.push.PushBody;
|
import org.whispersystems.textsecure.push.PushBody;
|
||||||
import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent;
|
import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent;
|
||||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
|
import org.whispersystems.textsecure.push.PushTransportDetails;
|
||||||
import org.whispersystems.textsecure.push.StaleDevices;
|
import org.whispersystems.textsecure.push.StaleDevices;
|
||||||
import org.whispersystems.textsecure.push.StaleDevicesException;
|
import org.whispersystems.textsecure.push.StaleDevicesException;
|
||||||
import org.whispersystems.textsecure.push.UnregisteredUserException;
|
import org.whispersystems.textsecure.push.UnregisteredUserException;
|
||||||
@ -344,8 +345,10 @@ public class PushTransport extends BaseTransport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, pushAddress);
|
||||||
SessionCipher cipher = SessionCipherFactory.getInstance(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();
|
int remoteRegistrationId = cipher.getRemoteRegistrationId();
|
||||||
|
|
||||||
if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
|
if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user