From d9d4ec9d9d7f05b05ebe6404215b78e1f3325573 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Tue, 11 Nov 2014 20:29:55 -0800 Subject: [PATCH] Fix some bugs with PKWM padding and attachment detection. --- .../whispersystems/libaxolotl/SessionCipher.java | 11 +++++++++++ .../textsecure/api/crypto/TextSecureCipher.java | 16 ++++++++-------- .../api/messages/TextSecureMessage.java | 7 ++++++- .../securesms/jobs/PushDecryptJob.java | 4 ++++ .../securesms/push/SecurityEventListener.java | 9 +++------ 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java index 6984966854..43e90d3c78 100644 --- a/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java +++ b/libaxolotl/src/main/java/org/whispersystems/libaxolotl/SessionCipher.java @@ -274,6 +274,17 @@ public class SessionCipher { } } + public int getSessionVersion() { + synchronized (SESSION_LOCK) { + if (!sessionStore.containsSession(recipientId, deviceId)) { + throw new IllegalStateException(String.format("No session for (%d, %d)!", recipientId, deviceId)); + } + + SessionRecord record = sessionStore.loadSession(recipientId, deviceId); + return record.getSessionState().getSessionVersion(); + } + } + private ChainKey getOrCreateChainKey(SessionState sessionState, ECPublicKey theirEphemeral) throws InvalidMessageException { diff --git a/library/src/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java b/library/src/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java index dfb2213efc..f4e1a557ef 100644 --- a/library/src/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java +++ b/library/src/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java @@ -1,5 +1,7 @@ package org.whispersystems.textsecure.api.crypto; +import android.util.Log; + import com.google.protobuf.InvalidProtocolBufferException; import org.whispersystems.libaxolotl.DuplicateMessageException; @@ -30,18 +32,14 @@ import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageCo public class TextSecureCipher { - private final SessionCipher sessionCipher; - private final PushTransportDetails transportDetails; + private final SessionCipher sessionCipher; public TextSecureCipher(AxolotlStore axolotlStore, long recipientId, int deviceId) { - int sessionVersion = axolotlStore.loadSession(recipientId, deviceId) - .getSessionState().getSessionVersion(); - - this.transportDetails = new PushTransportDetails(sessionVersion); - this.sessionCipher = new SessionCipher(axolotlStore, recipientId, deviceId); + this.sessionCipher = new SessionCipher(axolotlStore, recipientId, deviceId); } public CiphertextMessage encrypt(byte[] unpaddedMessage) { + PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion()); return sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage)); } @@ -63,7 +61,9 @@ public class TextSecureCipher { throw new InvalidMessageException("Unknown type: " + envelope.getType()); } - PushMessageContent content = PushMessageContent.parseFrom(transportDetails.getStrippedPaddingMessageBody(paddedMessage)); + PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion()); + PushMessageContent content = PushMessageContent.parseFrom(transportDetails.getStrippedPaddingMessageBody(paddedMessage)); + return createTextSecureMessage(envelope, content); } catch (InvalidProtocolBufferException e) { throw new InvalidMessageException(e); diff --git a/library/src/org/whispersystems/textsecure/api/messages/TextSecureMessage.java b/library/src/org/whispersystems/textsecure/api/messages/TextSecureMessage.java index 124556c6fd..b17a5626ba 100644 --- a/library/src/org/whispersystems/textsecure/api/messages/TextSecureMessage.java +++ b/library/src/org/whispersystems/textsecure/api/messages/TextSecureMessage.java @@ -27,11 +27,16 @@ public class TextSecureMessage { public TextSecureMessage(long timestamp, TextSecureGroup group, List attachments, String body, boolean secure, boolean endSession) { this.timestamp = timestamp; - this.attachments = Optional.fromNullable(attachments); this.body = Optional.fromNullable(body); this.group = Optional.fromNullable(group); this.secure = secure; this.endSession = endSession; + + if (attachments != null && !attachments.isEmpty()) { + this.attachments = Optional.of(attachments); + } else { + this.attachments = Optional.absent(); + } } public long getTimestamp() { diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 77fe5b0d5e..b98a984981 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -101,6 +101,10 @@ public class PushDecryptJob extends MasterSecretJob { else if (message.isGroupUpdate()) handleGroupMessage(masterSecret, envelope, message); else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, envelope, message); else handleTextMessage(masterSecret, envelope, message); + + if (envelope.isPreKeyWhisperMessage()) { + ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context)); + } } catch (InvalidVersionException e) { Log.w(TAG, e); handleInvalidVersionMessage(masterSecret, envelope); diff --git a/src/org/thoughtcrime/securesms/push/SecurityEventListener.java b/src/org/thoughtcrime/securesms/push/SecurityEventListener.java index 6ff2a12fc2..f6e03f6467 100644 --- a/src/org/thoughtcrime/securesms/push/SecurityEventListener.java +++ b/src/org/thoughtcrime/securesms/push/SecurityEventListener.java @@ -2,15 +2,16 @@ package org.thoughtcrime.securesms.push; import android.content.Context; -import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.SecurityEvent; import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; import org.whispersystems.textsecure.api.TextSecureMessageSender; public class SecurityEventListener implements TextSecureMessageSender.EventListener { + + private static final String TAG = SecurityEventListener.class.getSimpleName(); + private final Context context; public SecurityEventListener(Context context) { @@ -23,10 +24,6 @@ public class SecurityEventListener implements TextSecureMessageSender.EventListe long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); SecurityEvent.broadcastSecurityUpdateEvent(context, threadId); - - ApplicationContext.getInstance(context) - .getJobManager() - .add(new RefreshPreKeysJob(context)); } }