mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-03 12:32:17 +00:00
Rearrange decrypt API.
1) Change SessionBuilder to only establish sessions via KeyExchangeMessage and PreKeyBundles. 2) Change SessionCipher to decrypt either WhisperMessage or PreKeyWhisperMessage items, automatically building a session for the latter. 3) Change SessionCipher to tear down new sessions built with PreKeyWhisperMessages if the embedded WhsiperMessage fails to decrypt.
This commit is contained in:
@@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@@ -33,18 +34,24 @@ import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||
import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.StaleKeyExchangeException;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
@@ -53,8 +60,10 @@ import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyParcelable;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.push.PushTransportDetails;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.whispersystems.textsecure.util.InvalidNumberException;
|
||||
@@ -243,43 +252,36 @@ public class ReceiveKeyActivity extends Activity {
|
||||
}
|
||||
} else if (keyExchangeMessageBundle != null) {
|
||||
try {
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId);
|
||||
KeyExchangeProcessor processor = new KeyExchangeProcessor(ReceiveKeyActivity.this,
|
||||
masterSecret, recipientDevice);
|
||||
Context context = ReceiveKeyActivity.this;
|
||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId);
|
||||
|
||||
TransportDetails transportDetails = getIntent().getBooleanExtra("is_push", false) ?
|
||||
new PushTransportDetails(keyExchangeMessageBundle.getMessageVersion()) :
|
||||
new SmsTransportDetails();
|
||||
|
||||
TextSecureCipher cipher = new TextSecureCipher(ReceiveKeyActivity.this, masterSecret, recipientDevice, transportDetails);
|
||||
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(ReceiveKeyActivity.this,
|
||||
masterSecret);
|
||||
|
||||
identityKeyStore.saveIdentity(recipient.getRecipientId(), keyExchangeMessageBundle.getIdentityKey());
|
||||
processor.processKeyExchangeMessage(keyExchangeMessageBundle);
|
||||
byte[] plaintext = cipher.decrypt(keyExchangeMessageBundle);
|
||||
|
||||
CiphertextMessage bundledMessage = keyExchangeMessageBundle.getWhisperMessage();
|
||||
database.updateBundleMessageBody(masterSecret, messageId, "");
|
||||
database.updateMessageBody(masterSecret, messageId, new String(plaintext));
|
||||
|
||||
if (getIntent().getBooleanExtra("is_push", false)) {
|
||||
String source = Util.canonicalizeNumber(ReceiveKeyActivity.this, recipient.getNumber());
|
||||
IncomingPushMessage incoming = new IncomingPushMessage(Type.CIPHERTEXT_VALUE, source, recipientDeviceId, bundledMessage.serialize(), System.currentTimeMillis());
|
||||
|
||||
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
|
||||
.markAsProcessedKeyExchange(messageId);
|
||||
|
||||
Intent intent = new Intent(ReceiveKeyActivity.this, SendReceiveService.class);
|
||||
intent.setAction(SendReceiveService.RECEIVE_PUSH_ACTION);
|
||||
intent.putExtra("message", incoming);
|
||||
startService(intent);
|
||||
} else {
|
||||
SmsTransportDetails transportDetails = new SmsTransportDetails();
|
||||
String messageBody = new String(transportDetails.getEncodedMessage(bundledMessage.serialize()));
|
||||
|
||||
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
|
||||
.updateBundleMessageBody(masterSecret, messageId, messageBody);
|
||||
|
||||
DecryptingQueue.scheduleDecryption(ReceiveKeyActivity.this, masterSecret, messageId,
|
||||
threadId, recipient.getNumber(), recipientDeviceId,
|
||||
messageBody, true, false, false);
|
||||
}
|
||||
} catch (InvalidKeyIdException | InvalidNumberException | InvalidKeyException e) {
|
||||
} catch (InvalidKeyIdException | InvalidKeyException | LegacyMessageException | NoSessionException e) {
|
||||
Log.w("ReceiveKeyActivity", e);
|
||||
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
|
||||
.markAsCorruptKeyExchange(messageId);
|
||||
} catch (InvalidMessageException e) {
|
||||
Log.w("ReceiveKeyActivity", e);
|
||||
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
|
||||
.markAsDecryptFailed(messageId);
|
||||
} catch (DuplicateMessageException e) {
|
||||
Log.w("ReceiveKeyActivity", e);
|
||||
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
|
||||
.markAsDecryptDuplicate(messageId);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w("ReceiveKeyActivity", e);
|
||||
Toast.makeText(ReceiveKeyActivity.this, "Untrusted!", Toast.LENGTH_LONG).show();
|
||||
|
||||
@@ -44,14 +44,13 @@ import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.StaleKeyExchangeException;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
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;
|
||||
@@ -213,12 +212,12 @@ public class DecryptingQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, recipientDevice);
|
||||
TransportDetails transportDetails = new PushTransportDetails(sessionVersion);
|
||||
TextSecureCipher textSecureCipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
byte[] plaintextBody = textSecureCipher.decrypt(new WhisperMessage(message.getBody()));
|
||||
|
||||
message = message.withBody(transport.getStrippedPaddingMessageBody(plaintextBody));
|
||||
message = message.withBody(plaintextBody);
|
||||
sendResult(PushReceiver.RESULT_OK);
|
||||
} catch (InvalidMessageException | LegacyMessageException | RecipientFormattingException e) {
|
||||
Log.w("DecryptionQueue", e);
|
||||
@@ -226,6 +225,9 @@ public class DecryptingQueue {
|
||||
} catch (DuplicateMessageException e) {
|
||||
Log.w("DecryptingQueue", e);
|
||||
sendResult(PushReceiver.RESULT_DECRYPT_DUPLICATE);
|
||||
} catch (NoSessionException e) {
|
||||
Log.w("DecryptingQueue", e);
|
||||
sendResult(PushReceiver.RESULT_NO_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,12 +296,12 @@ public class DecryptingQueue {
|
||||
byte[] plaintextPduBytes;
|
||||
|
||||
Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes));
|
||||
TextTransport transportDetails = new TextTransport();
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes);
|
||||
TextTransport transportDetails = new TextTransport();
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
byte[] decodedCiphertext = transportDetails.getDecodedMessage(ciphertextPduBytes);
|
||||
|
||||
try {
|
||||
plaintextPduBytes = sessionCipher.decrypt(decodedCiphertext);
|
||||
plaintextPduBytes = cipher.decrypt(new WhisperMessage(decodedCiphertext));
|
||||
} catch (InvalidMessageException ime) {
|
||||
// XXX - For some reason, Sprint seems to append a single character to the
|
||||
// end of message text segments. I don't know why, so here we just try
|
||||
@@ -308,7 +310,7 @@ public class DecryptingQueue {
|
||||
Log.w("DecryptingQueue", "Attempting truncated decrypt...");
|
||||
byte[] truncated = Util.trim(ciphertextPduBytes, ciphertextPduBytes.length - 1);
|
||||
decodedCiphertext = transportDetails.getDecodedMessage(truncated);
|
||||
plaintextPduBytes = sessionCipher.decrypt(decodedCiphertext);
|
||||
plaintextPduBytes = cipher.decrypt(new WhisperMessage(decodedCiphertext));
|
||||
} else {
|
||||
throw ime;
|
||||
}
|
||||
@@ -329,6 +331,9 @@ public class DecryptingQueue {
|
||||
} catch (LegacyMessageException lme) {
|
||||
Log.w("DecryptingQueue", lme);
|
||||
database.markAsLegacyVersion(messageId, threadId);
|
||||
} catch (NoSessionException nse) {
|
||||
Log.w("DecryptingQueue", nse);
|
||||
database.markAsNoSession(messageId, threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,8 +387,8 @@ public class DecryptingQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] paddedPlaintext = sessionCipher.decrypt(decodedCiphertext);
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
byte[] paddedPlaintext = cipher.decrypt(new WhisperMessage(decodedCiphertext));
|
||||
|
||||
plaintextBody = new String(transportDetails.getStrippedPaddingMessageBody(paddedPlaintext));
|
||||
|
||||
@@ -405,6 +410,10 @@ public class DecryptingQueue {
|
||||
Log.w("DecryptionQueue", e);
|
||||
database.markAsDecryptDuplicate(messageId);
|
||||
return;
|
||||
} catch (NoSessionException e) {
|
||||
Log.w("DecryptingQueue", e);
|
||||
database.markAsNoSession(messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
database.updateMessageBody(masterSecret, messageId, plaintextBody);
|
||||
|
||||
@@ -57,13 +57,6 @@ public class KeyExchangeProcessor {
|
||||
recipientDevice.getDeviceId());
|
||||
}
|
||||
|
||||
public void processKeyExchangeMessage(PreKeyWhisperMessage message)
|
||||
throws InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
sessionBuilder.process(message);
|
||||
PreKeyService.initiateRefresh(context, masterSecret);
|
||||
}
|
||||
|
||||
public void processKeyExchangeMessage(PreKeyBundle bundle, long threadId)
|
||||
throws InvalidKeyException, UntrustedIdentityException
|
||||
{
|
||||
|
||||
67
src/org/thoughtcrime/securesms/crypto/TextSecureCipher.java
Normal file
67
src/org/thoughtcrime/securesms/crypto/TextSecureCipher.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyStore;
|
||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
||||
import org.whispersystems.libaxolotl.state.SignedPreKeyStore;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.TextSecurePreKeyStore;
|
||||
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
|
||||
|
||||
public class TextSecureCipher {
|
||||
|
||||
private final SessionCipher sessionCipher;
|
||||
private final TransportDetails transportDetails;
|
||||
|
||||
public TextSecureCipher(Context context, MasterSecret masterSecret,
|
||||
RecipientDevice recipient, TransportDetails transportDetails)
|
||||
{
|
||||
SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
|
||||
PreKeyStore preKeyStore = new TextSecurePreKeyStore(context, masterSecret);
|
||||
SignedPreKeyStore signedPreKeyStore = new TextSecurePreKeyStore(context, masterSecret);
|
||||
IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context, masterSecret);
|
||||
|
||||
this.transportDetails = transportDetails;
|
||||
this.sessionCipher = new SessionCipher(sessionStore, preKeyStore, signedPreKeyStore, identityKeyStore,
|
||||
recipient.getRecipientId(), recipient.getDeviceId());
|
||||
}
|
||||
|
||||
public CiphertextMessage encrypt(byte[] unpaddedMessage) {
|
||||
return sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
|
||||
}
|
||||
|
||||
public byte[] decrypt(WhisperMessage message)
|
||||
throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, NoSessionException
|
||||
{
|
||||
byte[] paddedMessage = sessionCipher.decrypt(message);
|
||||
return transportDetails.getStrippedPaddingMessageBody(paddedMessage);
|
||||
}
|
||||
|
||||
public byte[] decrypt(PreKeyWhisperMessage message)
|
||||
throws InvalidKeyException, LegacyMessageException, InvalidMessageException,
|
||||
DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException, NoSessionException
|
||||
{
|
||||
byte[] paddedMessage = sessionCipher.decrypt(message);
|
||||
return transportDetails.getStrippedPaddingMessageBody(paddedMessage);
|
||||
}
|
||||
|
||||
public int getRemoteRegistrationId() {
|
||||
return sessionCipher.getRemoteRegistrationId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -281,6 +281,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
|
||||
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.ENCRYPTION_REMOTE_LEGACY_BIT;
|
||||
else if (((IncomingKeyExchangeMessage)message).isDuplicate()) type |= Types.ENCRYPTION_REMOTE_DUPLICATE_BIT;
|
||||
else if (((IncomingKeyExchangeMessage)message).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT;
|
||||
} else if (message.isSecureMessage()) {
|
||||
type |= Types.SECURE_MESSAGE_BIT;
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@@ -24,16 +25,21 @@ import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||
import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.push.PushTransportDetails;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
@@ -113,34 +119,39 @@ public class PushReceiver {
|
||||
}
|
||||
|
||||
try {
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSource(), false).getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSourceDevice());
|
||||
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice);
|
||||
PreKeyWhisperMessage preKeyExchange = new PreKeyWhisperMessage(message.getBody());
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSource(), false).getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSourceDevice());
|
||||
PreKeyWhisperMessage preKeyWhisperMessage = new PreKeyWhisperMessage(message.getBody());
|
||||
TransportDetails transportDetails = new PushTransportDetails(preKeyWhisperMessage.getMessageVersion());
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
byte[] plaintext = cipher.decrypt(preKeyWhisperMessage);
|
||||
|
||||
try {
|
||||
processor.processKeyExchangeMessage(preKeyExchange);
|
||||
IncomingPushMessage bundledMessage = message.withBody(plaintext);
|
||||
handleReceivedMessage(masterSecret, bundledMessage, true);
|
||||
|
||||
IncomingPushMessage bundledMessage = message.withBody(preKeyExchange.getWhisperMessage().serialize());
|
||||
handleReceivedSecureMessage(masterSecret, bundledMessage);
|
||||
} catch (UntrustedIdentityException uie) {
|
||||
Log.w("PushReceiver", uie);
|
||||
String encoded = Base64.encodeBytes(message.getBody());
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(message, encoded, null);
|
||||
IncomingPreKeyBundleMessage bundleMessage = new IncomingPreKeyBundleMessage(textMessage, encoded);
|
||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox(masterSecret, bundleMessage);
|
||||
|
||||
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
|
||||
}
|
||||
} catch (InvalidVersionException e) {
|
||||
Log.w("PushReceiver", e);
|
||||
handleReceivedCorruptedKey(masterSecret, message, true);
|
||||
} catch (InvalidKeyException | InvalidKeyIdException | InvalidMessageException |
|
||||
RecipientFormattingException e)
|
||||
RecipientFormattingException | LegacyMessageException e)
|
||||
{
|
||||
Log.w("PushReceiver", e);
|
||||
handleReceivedCorruptedKey(masterSecret, message, false);
|
||||
} catch (DuplicateMessageException e) {
|
||||
Log.w("PushReceiver", e);
|
||||
handleReceivedDuplicateMessage(message);
|
||||
} catch (NoSessionException e) {
|
||||
Log.w("PushReceiver", e);
|
||||
handleReceivedMessageForNoSession(masterSecret, message);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w("PushReceiver", e);
|
||||
String encoded = Base64.encodeBytes(message.getBody());
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(message, encoded, null);
|
||||
IncomingPreKeyBundleMessage bundleMessage = new IncomingPreKeyBundleMessage(textMessage, encoded);
|
||||
Pair<Long, Long> messageAndThreadId = DatabaseFactory.getEncryptingSmsDatabase(context)
|
||||
.insertMessageInbox(masterSecret, bundleMessage);
|
||||
|
||||
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.util.Pair;
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
@@ -42,10 +43,12 @@ import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.StaleKeyExchangeException;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
|
||||
@@ -115,39 +118,47 @@ public class SmsReceiver {
|
||||
IncomingPreKeyBundleMessage message)
|
||||
{
|
||||
Log.w("SmsReceiver", "Processing prekey message...");
|
||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||
|
||||
try {
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSender(), false).getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSenderDeviceId());
|
||||
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice);
|
||||
SmsTransportDetails transportDetails = new SmsTransportDetails();
|
||||
byte[] rawMessage = transportDetails.getDecodedMessage(message.getMessageBody().getBytes());
|
||||
PreKeyWhisperMessage preKeyExchange = new PreKeyWhisperMessage(rawMessage);
|
||||
if (masterSecret != null) {
|
||||
try {
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSender(), false).getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSenderDeviceId());
|
||||
SmsTransportDetails transportDetails = new SmsTransportDetails();
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
byte[] rawMessage = transportDetails.getDecodedMessage(message.getMessageBody().getBytes());
|
||||
PreKeyWhisperMessage preKeyWhisperMessage = new PreKeyWhisperMessage(rawMessage);
|
||||
byte[] plaintext = cipher.decrypt(preKeyWhisperMessage);
|
||||
|
||||
processor.processKeyExchangeMessage(preKeyExchange);
|
||||
IncomingEncryptedMessage bundledMessage = new IncomingEncryptedMessage(message, new String(transportDetails.getEncodedMessage(preKeyWhisperMessage.getWhisperMessage().serialize())));
|
||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox(masterSecret, bundledMessage);
|
||||
|
||||
WhisperMessage ciphertextMessage = preKeyExchange.getWhisperMessage();
|
||||
String bundledMessageBody = new String(transportDetails.getEncodedMessage(ciphertextMessage.serialize()));
|
||||
IncomingEncryptedMessage bundledMessage = new IncomingEncryptedMessage(message, bundledMessageBody);
|
||||
Pair<Long, Long> messageAndThreadId = storeSecureMessage(masterSecret, bundledMessage);
|
||||
database.updateMessageBody(masterSecret, messageAndThreadId.first, new String(plaintext));
|
||||
|
||||
Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT);
|
||||
intent.putExtra("thread_id", messageAndThreadId.second);
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION);
|
||||
Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT);
|
||||
intent.putExtra("thread_id", messageAndThreadId.second);
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION);
|
||||
|
||||
return messageAndThreadId;
|
||||
} catch (InvalidKeyException | RecipientFormattingException | InvalidMessageException | IOException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setCorrupted(true);
|
||||
} catch (InvalidVersionException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setInvalidVersion(true);
|
||||
} catch (InvalidKeyIdException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setStale(true);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
return messageAndThreadId;
|
||||
} catch (InvalidKeyException | RecipientFormattingException | InvalidMessageException | IOException | NoSessionException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setCorrupted(true);
|
||||
} catch (InvalidVersionException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setInvalidVersion(true);
|
||||
} catch (InvalidKeyIdException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setStale(true);
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
} catch (DuplicateMessageException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setDuplicate(true);
|
||||
} catch (LegacyMessageException e) {
|
||||
Log.w("SmsReceiver", e);
|
||||
message.setLegacyVersion(true);
|
||||
}
|
||||
}
|
||||
|
||||
return storeStandardMessage(masterSecret, message);
|
||||
|
||||
@@ -7,6 +7,7 @@ public class IncomingKeyExchangeMessage extends IncomingTextMessage {
|
||||
private boolean isCorrupted;
|
||||
private boolean isInvalidVersion;
|
||||
private boolean isLegacyVersion;
|
||||
private boolean isDuplicate;
|
||||
|
||||
public IncomingKeyExchangeMessage(IncomingTextMessage base, String newBody) {
|
||||
super(base, newBody);
|
||||
@@ -69,6 +70,14 @@ public class IncomingKeyExchangeMessage extends IncomingTextMessage {
|
||||
this.isLegacyVersion = isLegacyVersion;
|
||||
}
|
||||
|
||||
public void setDuplicate(boolean isDuplicate) {
|
||||
this.isDuplicate = isDuplicate;
|
||||
}
|
||||
|
||||
public boolean isDuplicate() {
|
||||
return isDuplicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeyExchange() {
|
||||
return true;
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||
@@ -33,10 +34,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.SessionUtil;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
@@ -180,8 +179,8 @@ public class MmsTransport {
|
||||
throw new InsecureFallbackApprovalException("No session exists for this secure message.");
|
||||
}
|
||||
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
CiphertextMessage ciphertextMessage = sessionCipher.encrypt(pduBytes);
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
CiphertextMessage ciphertextMessage = cipher.encrypt(pduBytes);
|
||||
|
||||
return transportDetails.getEncodedMessage(ciphertextMessage.serialize());
|
||||
} catch (RecipientFormattingException e) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.util.Log;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
@@ -35,13 +36,12 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyBundle;
|
||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
||||
import org.whispersystems.textsecure.crypto.AttachmentCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
||||
import org.whispersystems.textsecure.crypto.TransportDetails;
|
||||
import org.whispersystems.textsecure.push.MismatchedDevices;
|
||||
import org.whispersystems.textsecure.push.MismatchedDevicesException;
|
||||
import org.whispersystems.textsecure.push.OutgoingPushMessage;
|
||||
@@ -345,10 +345,9 @@ public class PushTransport extends BaseTransport {
|
||||
}
|
||||
}
|
||||
|
||||
int sessionVersion = SessionUtil.getSessionVersion(context, masterSecret, pushAddress);
|
||||
SessionCipher cipher = SessionCipherFactory.getInstance(context, masterSecret, pushAddress);
|
||||
byte[] paddedPlaintext = new PushTransportDetails(sessionVersion).getPaddedMessageBody(plaintext);
|
||||
CiphertextMessage message = cipher.encrypt(paddedPlaintext);
|
||||
TransportDetails transportDetails = new PushTransportDetails(SessionUtil.getSessionVersion(context, masterSecret, pushAddress));
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, pushAddress, transportDetails);
|
||||
CiphertextMessage message = cipher.encrypt(plaintext);
|
||||
int remoteRegistrationId = cipher.getRemoteRegistrationId();
|
||||
|
||||
if (message.getType() == CiphertextMessage.PREKEY_TYPE) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.TextSecureCipher;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler;
|
||||
@@ -30,15 +31,10 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.state.SessionRecord;
|
||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipherFactory;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.SessionUtil;
|
||||
import org.whispersystems.textsecure.storage.TextSecureSessionStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -183,9 +179,8 @@ public class SmsTransport extends BaseTransport {
|
||||
|
||||
String body = message.getMessageBody();
|
||||
SmsTransportDetails transportDetails = new SmsTransportDetails();
|
||||
SessionCipher sessionCipher = SessionCipherFactory.getInstance(context, masterSecret, recipientDevice);
|
||||
byte[] paddedPlaintext = transportDetails.getPaddedMessageBody(body.getBytes());
|
||||
CiphertextMessage ciphertextMessage = sessionCipher.encrypt(paddedPlaintext);
|
||||
TextSecureCipher cipher = new TextSecureCipher(context, masterSecret, recipientDevice, transportDetails);
|
||||
CiphertextMessage ciphertextMessage = cipher.encrypt(body.getBytes());
|
||||
String encodedCiphertext = new String(transportDetails.getEncodedMessage(ciphertextMessage.serialize()));
|
||||
|
||||
if (ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE) {
|
||||
|
||||
Reference in New Issue
Block a user