mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
Correctly handle deferred processing of key exchange message when locked.
This commit is contained in:
parent
3d49e90779
commit
ad6760b62c
@ -18,8 +18,10 @@ package org.thoughtcrime.securesms.crypto;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
@ -71,11 +73,11 @@ public class DecryptingQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void scheduleDecryption(Context context, MasterSecret masterSecret,
|
public static void scheduleDecryption(Context context, MasterSecret masterSecret,
|
||||||
long messageId, String originator, String body,
|
long messageId, long threadId, String originator,
|
||||||
boolean isSecureMessage)
|
String body, boolean isSecureMessage, boolean isKeyExchange)
|
||||||
{
|
{
|
||||||
DecryptionWorkItem runnable = new DecryptionWorkItem(context, masterSecret, messageId,
|
DecryptionWorkItem runnable = new DecryptionWorkItem(context, masterSecret, messageId, threadId,
|
||||||
originator, body, isSecureMessage);
|
originator, body, isSecureMessage, isKeyExchange);
|
||||||
synchronized (workQueue) {
|
synchronized (workQueue) {
|
||||||
workQueue.add(runnable);
|
workQueue.add(runnable);
|
||||||
workQueue.notifyAll();
|
workQueue.notifyAll();
|
||||||
@ -122,11 +124,14 @@ public class DecryptingQueue {
|
|||||||
SmsMessageRecord record)
|
SmsMessageRecord record)
|
||||||
{
|
{
|
||||||
long messageId = record.getId();
|
long messageId = record.getId();
|
||||||
|
long threadId = record.getThreadId();
|
||||||
String body = record.getBody().getBody();
|
String body = record.getBody().getBody();
|
||||||
String originator = record.getIndividualRecipient().getNumber();
|
String originator = record.getIndividualRecipient().getNumber();
|
||||||
boolean isSecureMessage = record.isSecure();
|
boolean isSecureMessage = record.isSecure();
|
||||||
|
boolean isKeyExchange = record.isKeyExchange();
|
||||||
|
|
||||||
scheduleDecryption(context, masterSecret, messageId, originator, body, isSecureMessage);
|
scheduleDecryption(context, masterSecret, messageId, threadId,
|
||||||
|
originator, body, isSecureMessage, isKeyExchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MmsDecryptionItem implements Runnable {
|
private static class MmsDecryptionItem implements Runnable {
|
||||||
@ -208,21 +213,25 @@ public class DecryptingQueue {
|
|||||||
private static class DecryptionWorkItem implements Runnable {
|
private static class DecryptionWorkItem implements Runnable {
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
private final long threadId;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MasterSecret masterSecret;
|
private final MasterSecret masterSecret;
|
||||||
private final String body;
|
private final String body;
|
||||||
private final String originator;
|
private final String originator;
|
||||||
private final boolean isSecureMessage;
|
private final boolean isSecureMessage;
|
||||||
|
private final boolean isKeyExchange;
|
||||||
|
|
||||||
public DecryptionWorkItem(Context context, MasterSecret masterSecret, long messageId,
|
public DecryptionWorkItem(Context context, MasterSecret masterSecret, long messageId, long threadId,
|
||||||
String originator, String body, boolean isSecureMessage)
|
String originator, String body, boolean isSecureMessage, boolean isKeyExchange)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
|
this.threadId = threadId;
|
||||||
this.masterSecret = masterSecret;
|
this.masterSecret = masterSecret;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.originator = originator;
|
this.originator = originator;
|
||||||
this.isSecureMessage = isSecureMessage;
|
this.isSecureMessage = isSecureMessage;
|
||||||
|
this.isKeyExchange = isKeyExchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRemoteAsymmetricEncrypt() {
|
private void handleRemoteAsymmetricEncrypt() {
|
||||||
@ -266,18 +275,47 @@ public class DecryptingQueue {
|
|||||||
try {
|
try {
|
||||||
AsymmetricMasterCipher asymmetricMasterCipher = new AsymmetricMasterCipher(MasterSecretUtil.getAsymmetricMasterSecret(context, masterSecret));
|
AsymmetricMasterCipher asymmetricMasterCipher = new AsymmetricMasterCipher(MasterSecretUtil.getAsymmetricMasterSecret(context, masterSecret));
|
||||||
plaintextBody = asymmetricMasterCipher.decryptBody(body);
|
plaintextBody = asymmetricMasterCipher.decryptBody(body);
|
||||||
} catch (InvalidMessageException ime) {
|
|
||||||
Log.w("DecryptionQueue", ime);
|
if (isKeyExchange) {
|
||||||
database.markAsDecryptFailed(messageId);
|
handleKeyExchangeProcessing(plaintextBody);
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w("DecryptionQueue", e);
|
|
||||||
database.markAsDecryptFailed(messageId);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
database.updateMessageBody(masterSecret, messageId, plaintextBody);
|
database.updateMessageBody(masterSecret, messageId, plaintextBody);
|
||||||
MessageNotifier.updateNotification(context, masterSecret);
|
MessageNotifier.updateNotification(context, masterSecret);
|
||||||
|
} catch (InvalidMessageException ime) {
|
||||||
|
Log.w("DecryptionQueue", ime);
|
||||||
|
database.markAsDecryptFailed(messageId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("DecryptionQueue", e);
|
||||||
|
database.markAsDecryptFailed(messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleKeyExchangeProcessing(String plaintxtBody) {
|
||||||
|
if (PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getBoolean(ApplicationPreferencesActivity.AUTO_KEY_EXCHANGE_PREF, true))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Recipient recipient = new Recipient(null, originator, null, null);
|
||||||
|
KeyExchangeMessage keyExchangeMessage = new KeyExchangeMessage(plaintxtBody);
|
||||||
|
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient);
|
||||||
|
|
||||||
|
Log.w("DecryptingQuue", "KeyExchange with fingerprint: " + keyExchangeMessage.getPublicKey().getFingerprint());
|
||||||
|
|
||||||
|
if (processor.isStale(keyExchangeMessage)) {
|
||||||
|
DatabaseFactory.getEncryptingSmsDatabase(context).markAsStaleKeyExchange(messageId);
|
||||||
|
} else if (!processor.hasCompletedSession() ||
|
||||||
|
processor.hasSameSessionIdentity(keyExchangeMessage))
|
||||||
|
{
|
||||||
|
DatabaseFactory.getEncryptingSmsDatabase(context).markAsProcessedKeyExchange(messageId);
|
||||||
|
processor.processKeyExchangeMessage(keyExchangeMessage, threadId);
|
||||||
|
}
|
||||||
|
} catch (InvalidVersionException e) {
|
||||||
|
Log.w("DecryptingQueue", e);
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
Log.w("DecryptingQueue", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,6 +139,14 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markAsStaleKeyExchange(long id) {
|
||||||
|
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_STALE_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markAsProcessedKeyExchange(long id) {
|
||||||
|
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_PROCESSED_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
public void markAsDecryptFailed(long id) {
|
public void markAsDecryptFailed(long id) {
|
||||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
||||||
}
|
}
|
||||||
@ -213,7 +221,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
if (message.isKeyExchange()) {
|
if (message.isKeyExchange()) {
|
||||||
type |= Types.KEY_EXCHANGE_BIT;
|
type |= Types.KEY_EXCHANGE_BIT;
|
||||||
if (((IncomingKeyExchangeMessage)message).isStale()) type |= Types.KEY_EXCHANGE_STALE_BIT;
|
if (((IncomingKeyExchangeMessage)message).isStale()) type |= Types.KEY_EXCHANGE_STALE_BIT;
|
||||||
else if (((IncomingKeyExchangeMessage)message).isProcessed()) {Log.w("SmsDatabase", "Setting processed bit..."); type |= Types.KEY_EXCHANGE_PROCESSED_BIT;}
|
else if (((IncomingKeyExchangeMessage)message).isProcessed()) type |= Types.KEY_EXCHANGE_PROCESSED_BIT;
|
||||||
} else if (message.isSecureMessage()) {
|
} else if (message.isSecureMessage()) {
|
||||||
type |= Types.SECURE_MESSAGE_BIT;
|
type |= Types.SECURE_MESSAGE_BIT;
|
||||||
type |= Types.ENCRYPTION_REMOTE_BIT;
|
type |= Types.ENCRYPTION_REMOTE_BIT;
|
||||||
|
@ -56,7 +56,9 @@ public class SmsReceiver {
|
|||||||
private IncomingTextMessage assembleMessageFragments(List<IncomingTextMessage> messages) {
|
private IncomingTextMessage assembleMessageFragments(List<IncomingTextMessage> messages) {
|
||||||
IncomingTextMessage message = new IncomingTextMessage(messages);
|
IncomingTextMessage message = new IncomingTextMessage(messages);
|
||||||
|
|
||||||
if (WirePrefix.isEncryptedMessage(message.getMessageBody()) || WirePrefix.isKeyExchange(message.getMessageBody())) {
|
if (WirePrefix.isEncryptedMessage(message.getMessageBody()) ||
|
||||||
|
WirePrefix.isKeyExchange(message.getMessageBody()))
|
||||||
|
{
|
||||||
return multipartMessageHandler.processPotentialMultipartMessage(message);
|
return multipartMessageHandler.processPotentialMultipartMessage(message);
|
||||||
} else {
|
} else {
|
||||||
return message;
|
return message;
|
||||||
@ -69,8 +71,9 @@ public class SmsReceiver {
|
|||||||
|
|
||||||
if (masterSecret != null) {
|
if (masterSecret != null) {
|
||||||
DecryptingQueue.scheduleDecryption(context, masterSecret, messageAndThreadId.first,
|
DecryptingQueue.scheduleDecryption(context, masterSecret, messageAndThreadId.first,
|
||||||
|
messageAndThreadId.second,
|
||||||
message.getSender(), message.getMessageBody(),
|
message.getSender(), message.getMessageBody(),
|
||||||
message.isSecureMessage());
|
message.isSecureMessage(), message.isKeyExchange());
|
||||||
}
|
}
|
||||||
|
|
||||||
return messageAndThreadId;
|
return messageAndThreadId;
|
||||||
@ -92,7 +95,10 @@ public class SmsReceiver {
|
|||||||
private Pair<Long, Long> storeKeyExchangeMessage(MasterSecret masterSecret,
|
private Pair<Long, Long> storeKeyExchangeMessage(MasterSecret masterSecret,
|
||||||
IncomingKeyExchangeMessage message)
|
IncomingKeyExchangeMessage message)
|
||||||
{
|
{
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(ApplicationPreferencesActivity.AUTO_KEY_EXCHANGE_PREF, true)) {
|
if (masterSecret != null &&
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getBoolean(ApplicationPreferencesActivity.AUTO_KEY_EXCHANGE_PREF, true))
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
Recipient recipient = new Recipient(null, message.getSender(), null, null);
|
Recipient recipient = new Recipient(null, message.getSender(), null, null);
|
||||||
KeyExchangeMessage keyExchangeMessage = new KeyExchangeMessage(message.getMessageBody());
|
KeyExchangeMessage keyExchangeMessage = new KeyExchangeMessage(message.getMessageBody());
|
||||||
|
Loading…
Reference in New Issue
Block a user