diff --git a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java b/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
index 11d0d36d77..54ae1ff9d1 100644
--- a/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
+++ b/library/src/org/whispersystems/textsecure/crypto/SessionCipher.java
@@ -89,7 +89,14 @@ public class SessionCipher {
throws InvalidMessageException
{
try {
- KeyRecords records = getKeyRecords(context, masterSecret, recipient);
+ KeyRecords records = getKeyRecords(context, masterSecret, recipient);
+
+ if (messageVersion < records.getSessionRecord().getNegotiatedSessionVersion()) {
+ throw new InvalidMessageException("Message version: " + messageVersion +
+ " but negotiated session version: " +
+ records.getSessionRecord().getNegotiatedSessionVersion());
+ }
+
SessionKey sessionKey = getSessionKey(masterSecret, Cipher.DECRYPT_MODE, messageVersion, localIdentityKey, records, recipientKeyId, senderKeyId);
return new SessionCipherContext(records, sessionKey, senderKeyId,
recipientKeyId, nextKey, counter,
diff --git a/library/src/org/whispersystems/textsecure/storage/SessionRecord.java b/library/src/org/whispersystems/textsecure/storage/SessionRecord.java
index 6ec97e626f..de42a112c3 100644
--- a/library/src/org/whispersystems/textsecure/storage/SessionRecord.java
+++ b/library/src/org/whispersystems/textsecure/storage/SessionRecord.java
@@ -44,7 +44,8 @@ public class SessionRecord extends Record {
private int counter;
private byte[] localFingerprint;
private byte[] remoteFingerprint;
- private int sessionVersion;
+ private int negotiatedSessionVersion;
+ private int currentSessionVersion;
private IdentityKey identityKey;
private SessionKey sessionKeyRecord;
@@ -59,8 +60,8 @@ public class SessionRecord extends Record {
public SessionRecord(Context context, MasterSecret masterSecret, long recipientId) {
super(context, SESSIONS_DIRECTORY, recipientId+"");
- this.masterSecret = masterSecret;
- this.sessionVersion = 31337;
+ this.masterSecret = masterSecret;
+ this.currentSessionVersion = 31337;
loadData();
}
@@ -91,11 +92,19 @@ public class SessionRecord extends Record {
}
public int getSessionVersion() {
- return (sessionVersion == 31337 ? 0 : sessionVersion);
+ return (currentSessionVersion == 31337 ? 0 : currentSessionVersion);
+ }
+
+ public int getNegotiatedSessionVersion() {
+ return negotiatedSessionVersion;
+ }
+
+ public void setNegotiatedSessionVersion(int sessionVersion) {
+ this.negotiatedSessionVersion = sessionVersion;
}
public void setSessionVersion(int sessionVersion) {
- this.sessionVersion = sessionVersion;
+ this.currentSessionVersion = sessionVersion;
}
public int getCounter() {
@@ -169,10 +178,11 @@ public class SessionRecord extends Record {
writeInteger(counter, out);
writeBlob(localFingerprint, out);
writeBlob(remoteFingerprint, out);
- writeInteger(sessionVersion, out);
+ writeInteger(currentSessionVersion, out);
writeIdentityKey(out);
writeInteger(verifiedSessionKey ? 1 : 0, out);
writeInteger(prekeyBundleRequired ? 1 : 0, out);
+ writeInteger(negotiatedSessionVersion, out);
if (sessionKeyRecord != null)
writeBlob(sessionKeyRecord.serialize(), out);
@@ -193,20 +203,20 @@ public class SessionRecord extends Record {
// Sigh, always put a version number on everything.
if (!isValidVersionMarker(versionMarker)) {
- this.counter = versionMarker;
- this.localFingerprint = readBlob(in);
- this.remoteFingerprint = readBlob(in);
- this.sessionVersion = 31337;
+ this.counter = versionMarker;
+ this.localFingerprint = readBlob(in);
+ this.remoteFingerprint = readBlob(in);
+ this.currentSessionVersion = 31337;
if (in.available() != 0)
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
in.close();
} else {
- this.counter = readInteger(in);
- this.localFingerprint = readBlob(in);
- this.remoteFingerprint = readBlob(in);
- this.sessionVersion = readInteger(in);
+ this.counter = readInteger(in);
+ this.localFingerprint = readBlob (in);
+ this.remoteFingerprint = readBlob (in);
+ this.currentSessionVersion = readInteger(in);
if (versionMarker >= 0X55555556) {
readIdentityKey(in);
@@ -214,7 +224,10 @@ public class SessionRecord extends Record {
}
if (versionMarker >= 0X55555557) {
- this.prekeyBundleRequired = (readInteger(in) == 1);
+ this.prekeyBundleRequired = (readInteger(in) == 1);
+ this.negotiatedSessionVersion = readInteger(in);
+ } else {
+ this.negotiatedSessionVersion = currentSessionVersion;
}
if (in.available() != 0)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a5cee015e8..aceeb60fda 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -188,6 +188,8 @@
signature on this key exchange is trusted, but you have the \'automatically complete key
exchanges\' setting disabled.
+ Processing
+ Processing key exchange…
Connect With TextSecure
@@ -246,6 +248,18 @@
Registration Error
TextSecure registration has encountered a problem.
+
+ Received corrupted key
+ exchange message!
+
+
+ Received key exchange message for invalid protocol version.
+
+
+ Received message with unknown identity key. Click to process and display.
+
+
+
You do not have an identity key.
Recipient has no identity key.
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index 9fbd95d39a..178c0bb654 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -336,6 +336,7 @@ public class ConversationItem extends LinearLayout {
intent.putExtra("body", messageRecord.getBody().getBody());
intent.putExtra("thread_id", messageRecord.getThreadId());
intent.putExtra("message_id", messageRecord.getId());
+ intent.putExtra("is_bundle", messageRecord.isBundleKeyExchange());
intent.putExtra("master_secret", masterSecret);
intent.putExtra("sent", messageRecord.isOutgoing());
context.startActivity(intent);
diff --git a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
index 0e38236035..b4373011d4 100644
--- a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
+++ b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
@@ -30,6 +30,8 @@ import android.view.View;
import android.widget.Button;
import android.widget.TextView;
+import org.thoughtcrime.securesms.crypto.DecryptingQueue;
+import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage;
@@ -38,6 +40,10 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.MemoryCleaner;
+import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
+import org.whispersystems.textsecure.storage.InvalidKeyIdException;
+
+import java.io.IOException;
/**
* Activity for displaying sent/received session keys.
@@ -57,6 +63,7 @@ public class ReceiveKeyActivity extends Activity {
private long messageId;
private MasterSecret masterSecret;
+ private PreKeyBundleMessage keyExchangeMessageBundle;
private KeyExchangeMessage keyExchangeMessage;
private KeyExchangeProcessor keyExchangeProcessor;
@@ -85,8 +92,8 @@ public class ReceiveKeyActivity extends Activity {
}
private void initializeText() {
- if (keyExchangeProcessor.isTrusted(keyExchangeMessage)) initializeTrustedText();
- else initializeUntrustedText();
+ if (isTrusted(keyExchangeMessage, keyExchangeMessageBundle)) initializeTrustedText();
+ else initializeUntrustedText();
}
private void initializeTrustedText() {
@@ -102,6 +109,9 @@ public class ReceiveKeyActivity extends Activity {
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
intent.putExtra("recipient", recipient);
intent.putExtra("master_secret", masterSecret);
+ intent.putExtra("remote_identity",
+ keyExchangeMessage == null ?
+ keyExchangeMessageBundle.getIdentityKey() : keyExchangeMessage.getIdentityKey());
startActivity(intent);
}
}, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1,
@@ -111,9 +121,26 @@ public class ReceiveKeyActivity extends Activity {
descriptionText.setMovementMethod(LinkMovementMethod.getInstance());
}
+ private boolean isTrusted(KeyExchangeMessage message, PreKeyBundleMessage messageBundle) {
+ return (message != null && keyExchangeProcessor.isTrusted(message)) ||
+ (messageBundle != null && keyExchangeProcessor.isTrusted(messageBundle));
+ }
+
private void initializeKey() throws InvalidKeyException, InvalidVersionException {
- String messageBody = getIntent().getStringExtra("body");
- this.keyExchangeMessage = new KeyExchangeMessage(messageBody);
+ try {
+ String messageBody = getIntent().getStringExtra("body");
+
+ if (getIntent().getBooleanExtra("is_bundle", false)) {
+ SmsTransportDetails transportDetails = new SmsTransportDetails();
+ byte[] body = transportDetails.getDecodedMessage(messageBody.getBytes());
+
+ this.keyExchangeMessageBundle = new PreKeyBundleMessage(body);
+ } else {
+ this.keyExchangeMessage = new KeyExchangeMessage(messageBody);
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
}
private void initializeResources() {
@@ -123,7 +150,7 @@ public class ReceiveKeyActivity extends Activity {
this.recipient = getIntent().getParcelableExtra("recipient");
this.threadId = getIntent().getLongExtra("thread_id", -1);
this.messageId = getIntent().getLongExtra("message_id", -1);
- this.masterSecret = (MasterSecret)getIntent().getParcelableExtra("master_secret");
+ this.masterSecret = getIntent().getParcelableExtra("master_secret");
this.keyExchangeProcessor = new KeyExchangeProcessor(this, masterSecret, recipient);
}
@@ -140,15 +167,39 @@ public class ReceiveKeyActivity extends Activity {
@Override
protected void onPreExecute() {
- dialog = ProgressDialog.show(ReceiveKeyActivity.this, "Processing",
- "Processing key exchange...", true);
+ dialog = ProgressDialog.show(ReceiveKeyActivity.this,
+ getString(R.string.ReceiveKeyActivity_processing),
+ getString(R.string.ReceiveKeyActivity_processing_key_exchange),
+ true);
}
@Override
protected Void doInBackground(Void... params) {
- keyExchangeProcessor.processKeyExchangeMessage(keyExchangeMessage, threadId);
- DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
- .markAsProcessedKeyExchange(messageId);
+ if (keyExchangeMessage != null) {
+ keyExchangeProcessor.processKeyExchangeMessage(keyExchangeMessage, threadId);
+ DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
+ .markAsProcessedKeyExchange(messageId);
+ } else if (keyExchangeMessageBundle != null) {
+ try {
+ keyExchangeProcessor.processKeyExchangeMessage(keyExchangeMessageBundle);
+ byte[] bundledMessage = keyExchangeMessageBundle.getBundledMessage();
+ SmsTransportDetails transportDetails = new SmsTransportDetails();
+ String messageBody = new String(transportDetails.getEncodedMessage(bundledMessage));
+
+ DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
+ .updateBundleMessageBody(masterSecret, messageId, messageBody);
+
+ DecryptingQueue.scheduleDecryption(ReceiveKeyActivity.this, masterSecret, messageId,
+ threadId, recipient.getNumber(), messageBody,
+ true, false);
+ } catch (InvalidKeyIdException e) {
+ Log.w("ReceiveKeyActivity", e);
+ DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
+ .markAsCorruptKeyExchange(messageId);
+ }
+ }
+
+
return null;
}
diff --git a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java
index 062004ab9b..5c8763d2cb 100644
--- a/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java
+++ b/src/org/thoughtcrime/securesms/VerifyIdentityActivity.java
@@ -66,8 +66,12 @@ public class VerifyIdentityActivity extends KeyScanningActivity {
}
private void initializeRemoteIdentityKey() {
- SessionRecord sessionRecord = new SessionRecord(this, masterSecret, recipient);
- IdentityKey identityKey = sessionRecord.getIdentityKey();
+ IdentityKey identityKey = getIntent().getParcelableExtra("remote_identity");
+
+ if (identityKey == null) {
+ SessionRecord sessionRecord = new SessionRecord(this, masterSecret, recipient);
+ identityKey = sessionRecord.getIdentityKey();
+ }
if (identityKey == null) {
remoteIdentityFingerprint.setText(R.string.VerifyIdentityActivity_recipient_has_no_identity_key);
diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java
index 8a452db32d..781041f116 100644
--- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java
+++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java
@@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.util.Medium;
/**
* This class processes key exchange interactions.
@@ -131,13 +132,15 @@ public class KeyExchangeProcessor {
remoteKeyRecord.getCurrentRemoteKey().getFingerprintBytes());
sessionRecord.setIdentityKey(remoteIdentity);
sessionRecord.setSessionVersion(Math.min(message.getSupportedVersion(), MessageCipher.SUPPORTED_VERSION));
-
+ sessionRecord.setNegotiatedSessionVersion(sessionRecord.getSessionVersion());
localKeyRecord.save();
remoteKeyRecord.save();
sessionRecord.save();
- PreKeyRecord.delete(context, preKeyId);
+ if (preKeyId != Medium.MAX_VALUE) {
+ PreKeyRecord.delete(context, preKeyId);
+ }
DatabaseFactory.getIdentityDatabase(context)
.saveIdentity(masterSecret, recipient, remoteIdentity);
@@ -156,6 +159,7 @@ public class KeyExchangeProcessor {
sessionRecord.setSessionId(localKeyRecord.getCurrentKeyPair().getPublicKey().getFingerprintBytes(),
remoteKeyRecord.getCurrentRemoteKey().getFingerprintBytes());
sessionRecord.setIdentityKey(message.getIdentityKey());
+ sessionRecord.setNegotiatedSessionVersion(MessageCipher.SUPPORTED_VERSION);
sessionRecord.setSessionVersion(MessageCipher.SUPPORTED_VERSION);
sessionRecord.setPrekeyBundleRequired(true);
sessionRecord.save();
@@ -185,6 +189,7 @@ public class KeyExchangeProcessor {
remoteKeyRecord.getCurrentRemoteKey().getFingerprintBytes());
sessionRecord.setIdentityKey(message.getIdentityKey());
sessionRecord.setSessionVersion(Math.min(MessageCipher.SUPPORTED_VERSION, message.getMaxVersion()));
+ sessionRecord.setNegotiatedSessionVersion(sessionRecord.getSessionVersion());
Log.w("KeyExchangeUtil", "Setting session version: " + Math.min(MessageCipher.SUPPORTED_VERSION, message.getMaxVersion()));
diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java
index 9d0e6143f5..11aa016393 100644
--- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java
+++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java
@@ -29,6 +29,7 @@ import org.whispersystems.textsecure.crypto.PublicKey;
import org.whispersystems.textsecure.storage.LocalKeyRecord;
import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Conversions;
+import org.whispersystems.textsecure.util.Util;
import java.io.IOException;
@@ -70,20 +71,26 @@ public class KeyExchangeMessage {
this.supportedVersion = MessageCipher.SUPPORTED_VERSION;
publicKey.setId(publicKey.getId() | (highIdBits << 12));
-
+
+ byte[] versionBytes = {Conversions.intsToByteHighAndLow(messageVersion, supportedVersion)};
byte[] publicKeyBytes = publicKey.serialize();
- byte[] keyExchangeBytes = new byte[1 + publicKeyBytes.length];
-
- keyExchangeBytes[0] = Conversions.intsToByteHighAndLow(messageVersion, supportedVersion);
- System.arraycopy(publicKeyBytes, 0, keyExchangeBytes, 1, publicKeyBytes.length);
- if (includeIdentitySignature(messageVersion, context))
- keyExchangeBytes = IdentityKeyUtil.getSignedKeyExchange(context, masterSecret, keyExchangeBytes);
+ byte[] serializedBytes;
- if (messageVersion < 1)
- this.serialized = Base64.encodeBytes(keyExchangeBytes);
- else
- this.serialized = Base64.encodeBytesWithoutPadding(keyExchangeBytes);
+ if (includeIdentityNoSignature(messageVersion, context)) {
+ byte[] identityKey = IdentityKeyUtil.getIdentityKey(context).serialize();
+
+ serializedBytes = Util.combine(versionBytes, publicKeyBytes, identityKey);
+ } else if (includeIdentitySignature(messageVersion, context)) {
+ byte[] prolog = Util.combine(versionBytes, publicKeyBytes);
+
+ serializedBytes = IdentityKeyUtil.getSignedKeyExchange(context, masterSecret, prolog);
+ } else {
+ serializedBytes = Util.combine(versionBytes, publicKeyBytes);
+ }
+
+ if (messageVersion < 1) this.serialized = Base64.encodeBytes(serializedBytes);
+ else this.serialized = Base64.encodeBytesWithoutPadding(serializedBytes);
}
public KeyExchangeMessage(String messageBody) throws InvalidVersionException, InvalidKeyException {
@@ -104,23 +111,33 @@ public class KeyExchangeMessage {
if (keyBytes.length <= PublicKey.KEY_SIZE + 1) {
this.identityKey = null;
- } else {
+ } else if (messageVersion == 1) {
try {
this.identityKey = IdentityKeyUtil.verifySignedKeyExchange(keyBytes);
} catch (InvalidKeyException ike) {
Log.w("KeyUtil", ike);
this.identityKey = null;
}
- }
+ } else if (messageVersion == 2) {
+ try {
+ this.identityKey = new IdentityKey(keyBytes, 1 + PublicKey.KEY_SIZE);
+ } catch (InvalidKeyException ike) {
+ Log.w("KeyUtil", ike);
+ this.identityKey = null;
+ }
+ }
} catch (IOException ioe) {
throw new InvalidKeyException(ioe);
}
}
private static boolean includeIdentitySignature(int messageVersion, Context context) {
- return IdentityKeyUtil.hasIdentityKey(context) && (messageVersion >= 1);
+ return IdentityKeyUtil.hasIdentityKey(context) && (messageVersion == 1);
}
+ private static boolean includeIdentityNoSignature(int messageVersion, Context context) {
+ return IdentityKeyUtil.hasIdentityKey(context) && (messageVersion >= 2);
+ }
public PublicKey getPublicKey() {
return publicKey;
diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java
index 3315f7ada0..f88ec7ca65 100644
--- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java
+++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java
@@ -628,7 +628,7 @@ public class DatabaseFactory {
if (oldVersion < INTRODUCED_PUSH_DATABASE_VERSION) {
db.execSQL("CREATE TABLE push (_id INTEGER PRIMARY KEY, type INTEGER, source TEXT, destinations TEXT, body TEXT, TIMESTAMP INTEGER);");
db.execSQL("ALTER TABLE part ADD COLUMN pending_push INTEGER;");
- db.execSQL("CREATE INDEX IF NOT EXISTS pending_push_index ON parts (pending_push);");
+ db.execSQL("CREATE INDEX IF NOT EXISTS pending_push_index ON part (pending_push);");
}
db.setTransactionSuccessful();
diff --git a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java
index d4ed2f0f4b..a3a3eeaf58 100644
--- a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java
@@ -96,6 +96,11 @@ public class EncryptingSmsDatabase extends SmsDatabase {
return insertMessageInbox(message, type);
}
+ public void updateBundleMessageBody(MasterSecret masterSecret, long messageId, String body) {
+ updateMessageBodyAndType(messageId, body, Types.TOTAL_MASK,
+ Types.BASE_INBOX_TYPE | Types.ENCRYPTION_REMOTE_BIT | Types.SECURE_MESSAGE_BIT);
+ }
+
public void updateMessageBody(MasterSecret masterSecret, long messageId, String body) {
String encryptedBody = getEncryptedBody(masterSecret, body);
updateMessageBodyAndType(messageId, encryptedBody, Types.ENCRYPTION_MASK,
diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
index 0579d1dd4e..9bdba4565c 100644
--- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
+++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
@@ -32,6 +32,7 @@ public interface MmsSmsColumns {
protected static final long KEY_EXCHANGE_PROCESSED_BIT = 0x2000;
protected static final long KEY_EXCHANGE_CORRUPTED_BIT = 0x1000;
protected static final long KEY_EXCHANGE_INVALID_VERSION_BIT = 0x800;
+ protected static final long KEY_EXCHANGE_BUNDLE_BIT = 0x400;
// Secure Message Information
protected static final long SECURE_MESSAGE_BIT = 0x800000;
@@ -91,6 +92,10 @@ public interface MmsSmsColumns {
return (type & KEY_EXCHANGE_INVALID_VERSION_BIT) != 0;
}
+ public static boolean isBundleKeyExchange(long type) {
+ return (type & KEY_EXCHANGE_BUNDLE_BIT) != 0;
+ }
+
public static boolean isSymmetricEncryption(long type) {
return (type & ENCRYPTION_SYMMETRIC_BIT) != 0;
}
diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
index 703d43ac5b..06800a3d20 100644
--- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -162,6 +162,10 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_PROCESSED_BIT);
}
+ public void markAsCorruptKeyExchange(long id) {
+ updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_CORRUPTED_BIT);
+ }
+
public void markAsDecryptFailed(long id) {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
}
@@ -239,6 +243,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
else if (((IncomingKeyExchangeMessage)message).isProcessed()) type |= Types.KEY_EXCHANGE_PROCESSED_BIT;
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).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT;
} else if (message.isSecureMessage()) {
type |= Types.SECURE_MESSAGE_BIT;
type |= Types.ENCRYPTION_REMOTE_BIT;
diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
index ec43b0843e..db8f6611f0 100644
--- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
@@ -103,6 +103,10 @@ public abstract class MessageRecord extends DisplayRecord {
return SmsDatabase.Types.isProcessedKeyExchange(type);
}
+ public boolean isBundleKeyExchange() {
+ return SmsDatabase.Types.isBundleKeyExchange(type);
+ }
+
public boolean isCorruptedKeyExchange() {
return SmsDatabase.Types.isCorruptedKeyExchange(type);
}
diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
index 41dd394c0f..3347b02ebc 100644
--- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
@@ -56,6 +56,12 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.ConversationItem_received_and_processed_key_exchange_message));
} else if (isStaleKeyExchange()) {
return emphasisAdded(context.getString(R.string.ConversationItem_error_received_stale_key_exchange_message));
+ } else if (isCorruptedKeyExchange()) {
+ 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 (isBundleKeyExchange()) {
+ return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process));
} else if (isKeyExchange() && isOutgoing()) {
return emphasisAdded(context.getString(R.string.ConversationListAdapter_key_exchange_message));
} else if (isKeyExchange() && !isOutgoing()) {
diff --git a/src/org/thoughtcrime/securesms/service/PushReceiver.java b/src/org/thoughtcrime/securesms/service/PushReceiver.java
index ce7fc3d9b9..ead7b8dab4 100644
--- a/src/org/thoughtcrime/securesms/service/PushReceiver.java
+++ b/src/org/thoughtcrime/securesms/service/PushReceiver.java
@@ -18,7 +18,10 @@ import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage;
+import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
+import org.thoughtcrime.securesms.sms.SmsTransportDetails;
+import org.thoughtcrime.securesms.transport.SmsTransport;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException;
@@ -99,7 +102,12 @@ public class PushReceiver {
IncomingPushMessage bundledMessage = message.withBody(preKeyExchange.getBundledMessage());
handleReceivedSecureMessage(masterSecret, bundledMessage);
} else {
- /// XXX
+ SmsTransportDetails transportDetails = new SmsTransportDetails();
+ String encoded = new String(transportDetails.getEncodedMessage(message.getBody()));
+ IncomingTextMessage textMessage = new IncomingTextMessage(message, "");
+
+ textMessage = new IncomingPreKeyBundleMessage(textMessage, encoded);
+ DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, textMessage);
}
} catch (InvalidKeyException e) {
Log.w("SmsReceiver", e);
@@ -118,6 +126,7 @@ public class PushReceiver {
boolean secure)
{
try {
+ Log.w("PushReceiver", "Processing: " + new String(message.getBody()));
PushMessageContent messageContent = PushMessageContent.parseFrom(message.getBody());
if (messageContent.getAttachmentsCount() > 0 || message.getDestinations().size() > 0) {
diff --git a/src/org/thoughtcrime/securesms/service/SmsReceiver.java b/src/org/thoughtcrime/securesms/service/SmsReceiver.java
index 528da2a4ca..bf0b205c82 100644
--- a/src/org/thoughtcrime/securesms/service/SmsReceiver.java
+++ b/src/org/thoughtcrime/securesms/service/SmsReceiver.java
@@ -120,8 +120,6 @@ public class SmsReceiver {
context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION);
return messageAndThreadId;
- } else {
- /// XXX
}
} catch (InvalidKeyException e) {
Log.w("SmsReceiver", e);