diff --git a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java index 7b20211cd..534397ac8 100644 --- a/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java +++ b/library/src/org/whispersystems/textsecure/crypto/protocol/WhisperMessage.java @@ -133,4 +133,9 @@ public class WhisperMessage implements CiphertextMessage { return CiphertextMessage.WHISPER_TYPE; } + public static boolean isLegacy(byte[] message) { + return message != null && message.length >= 1 && + Conversions.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION; + } + } diff --git a/res/values/strings.xml b/res/values/strings.xml index ad08d51d5..c9e91fa0a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -200,6 +200,9 @@ Multimedia Message + + Message encrypted with a legacy protocol version that is no longer supported. Please ask the sender to upgrade TextSecure to the most recent version. + Passphrases Don\'t Match! Incorrect old passphrase! diff --git a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java index e0aa0faf1..36955d91e 100644 --- a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java +++ b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java @@ -47,6 +47,7 @@ import org.whispersystems.textsecure.crypto.InvalidMessageException; import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.SessionCipher; +import org.whispersystems.textsecure.crypto.protocol.WhisperMessage; import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.RecipientDevice; import org.whispersystems.textsecure.storage.Session; @@ -375,15 +376,17 @@ public class DecryptingQueue { Recipient recipient = recipients.getPrimaryRecipient(); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), deviceId); + SmsTransportDetails transportDetails = new SmsTransportDetails(); + byte[] decodedCiphertext = transportDetails.getDecodedMessage(body.getBytes()); + if (!Session.hasSession(context, masterSecret, recipient)) { - database.markAsNoSession(messageId); + if (WhisperMessage.isLegacy(decodedCiphertext)) database.markAsLegacyVersion(messageId); + else database.markAsNoSession(messageId); return; } - SmsTransportDetails transportDetails = new SmsTransportDetails(); - SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); - byte[] decodedCiphertext = transportDetails.getDecodedMessage(body.getBytes()); - byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext); + SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice); + byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext); plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext)); diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index d56095b0d..3d4a39841 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -363,7 +363,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { } public void markAsLegacyVersion(long messageId, long threadId) { - updateMailboxBitmask(messageId, 0, Types.LEGACY_MESSAGE_BIT); + updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT); notifyConversationListeners(threadId); } diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 57fda6b66..e7b602233 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -47,7 +47,6 @@ public interface MmsSmsColumns { protected static final long SECURE_MESSAGE_BIT = 0x800000; protected static final long END_SESSION_BIT = 0x400000; protected static final long PUSH_MESSAGE_BIT = 0x200000; - protected static final long LEGACY_MESSAGE_BIT = 0x100000; // Group Message Information protected static final long GROUP_UPDATE_BIT = 0x10000; @@ -61,6 +60,7 @@ public interface MmsSmsColumns { protected static final long ENCRYPTION_REMOTE_FAILED_BIT = 0x10000000; protected static final long ENCRYPTION_REMOTE_NO_SESSION_BIT = 0x08000000; protected static final long ENCRYPTION_REMOTE_DUPLICATE_BIT = 0x04000000; + protected static final long ENCRYPTION_REMOTE_LEGACY_BIT = 0x02000000; public static boolean isFailedMessageType(long type) { return (type & BASE_TYPE_MASK) == BASE_SENT_FAILED_TYPE; @@ -172,6 +172,10 @@ public interface MmsSmsColumns { return (type & ENCRYPTION_REMOTE_NO_SESSION_BIT) != 0; } + public static boolean isLegacyType(long type) { + return (type & ENCRYPTION_REMOTE_LEGACY_BIT) != 0; + } + public static long translateFromSystemBaseType(long theirType) { // public static final int NONE_TYPE = 0; // public static final int INBOX_TYPE = 1; diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 7140266de..b57bbb3c7 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -170,10 +170,6 @@ public class SmsDatabase extends Database implements MmsSmsColumns { updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_INVALID_VERSION_BIT); } - public void markAsLegacyVersion(long id) { - updateTypeBitmask(id, 0, Types.LEGACY_MESSAGE_BIT); - } - public void markAsSecure(long id) { updateTypeBitmask(id, 0, Types.SECURE_MESSAGE_BIT); } @@ -206,6 +202,10 @@ public class SmsDatabase extends Database implements MmsSmsColumns { updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_BIT); } + public void markAsLegacyVersion(long id) { + updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT); + } + public void markAsOutbox(long id) { updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_OUTBOX_TYPE); } @@ -280,7 +280,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns { else if (((IncomingKeyExchangeMessage)message).isCorrupted()) type |= Types.KEY_EXCHANGE_CORRUPTED_BIT; else if (((IncomingKeyExchangeMessage)message).isInvalidVersion()) type |= Types.KEY_EXCHANGE_INVALID_VERSION_BIT; else if (((IncomingKeyExchangeMessage)message).isIdentityUpdate()) type |= Types.KEY_EXCHANGE_IDENTITY_UPDATE_BIT; - else if (((IncomingKeyExchangeMessage)message).isLegacyVersion()) type |= Types.LEGACY_MESSAGE_BIT; + else if (((IncomingKeyExchangeMessage)message).isLegacyVersion()) type |= Types.ENCRYPTION_REMOTE_LEGACY_BIT; else if (((IncomingKeyExchangeMessage)message).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT; } else if (message.isSecureMessage()) { type |= Types.SECURE_MESSAGE_BIT; diff --git a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 1fd4b4056..49d4bcf58 100644 --- a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -78,6 +78,8 @@ public class MediaMmsMessageRecord extends MessageRecord { return emphasisAdded(context.getString(R.string.SmsMessageRecord_duplicate_message)); } else if (MmsDatabase.Types.isNoRemoteSessionType(type)) { return emphasisAdded(context.getString(R.string.MmsMessageRecord_mms_message_encrypted_for_non_existing_session)); + } else if (isLegacyMessage()) { + return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported)); } else if (!getBody().isPlaintext()) { return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message)); } diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java index 8d8790551..903c5e2c1 100644 --- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -81,6 +81,10 @@ public abstract class MessageRecord extends DisplayRecord { return MmsSmsColumns.Types.isSecureType(type); } + public boolean isLegacyMessage() { + return MmsSmsColumns.Types.isLegacyType(type); + } + @Override public SpannableString getDisplayBody() { if (isGroupUpdate() && isOutgoing()) { diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java index 0e1891314..1dce659d2 100644 --- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java @@ -21,6 +21,7 @@ import android.content.Context; import android.text.SpannableString; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.protocol.Tag; import org.thoughtcrime.securesms.recipients.Recipient; @@ -63,6 +64,8 @@ public class SmsMessageRecord extends MessageRecord { return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_corrupted_key_exchange_message)); } else if (isInvalidVersionKeyExchange()) { return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version)); + } else if (MmsSmsColumns.Types.isLegacyType(type)) { + return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported)); } else if (isBundleKeyExchange()) { return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process)); } else if (isIdentityUpdate()) { diff --git a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java index 7aec770a3..f13d7d934 100644 --- a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -22,6 +22,7 @@ import android.text.SpannableString; import android.text.style.StyleSpan; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.GroupUtil; @@ -69,6 +70,8 @@ public class ThreadRecord extends DisplayRecord { return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message)); } else if (SmsDatabase.Types.isEndSessionType(type)) { return emphasisAdded(context.getString(R.string.TheadRecord_secure_session_ended)); + } else if (MmsSmsColumns.Types.isLegacyType(type)) { + return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported)); } else { if (Util.isEmpty(getBody().getBody())) { return new SpannableString(context.getString(R.string.MessageNotifier_no_subject));