diff --git a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java index ce6b07ba07..f4a06a553a 100644 --- a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java +++ b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java @@ -32,7 +32,6 @@ import android.widget.TextView; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; -import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.recipients.Recipient; @@ -148,19 +147,12 @@ public class ReceiveKeyActivity extends Activity { } private boolean isTrusted(KeyExchangeMessage message, PreKeyWhisperMessage messageBundle, IdentityKey identityUpdateMessage) { - RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId); + RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId); + KeyExchangeProcessor processor = new KeyExchangeProcessor(this, masterSecret, recipientDevice); - if (message != null) { - KeyExchangeProcessor processor = KeyExchangeProcessor.createFor(this, masterSecret, - recipientDevice, message); - return processor.isTrusted(message); - } else if (messageBundle != null) { - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice); - return processor.isTrusted(messageBundle); - } else if (identityUpdateMessage != null) { - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice); - return processor.isTrusted(identityUpdateMessage); - } + if (message != null) return processor.isTrusted(message); + else if (messageBundle != null) return processor.isTrusted(messageBundle); + else if (identityUpdateMessage != null) return processor.isTrusted(identityUpdateMessage); return false; } @@ -186,7 +178,7 @@ public class ReceiveKeyActivity extends Activity { } else if (getIntent().getBooleanExtra("is_identity_update", false)) { this.identityUpdateMessage = new IdentityKey(Base64.decodeWithoutPadding(messageBody), 0); } else { - this.keyExchangeMessage = KeyExchangeMessage.createFor(messageBody); + this.keyExchangeMessage = new KeyExchangeMessage(messageBody); } } catch (IOException e) { throw new AssertionError(e); @@ -227,9 +219,13 @@ public class ReceiveKeyActivity extends Activity { protected Void doInBackground(Void... params) { if (keyExchangeMessage != null) { try { - RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId); - KeyExchangeProcessor processor = KeyExchangeProcessor.createFor(ReceiveKeyActivity.this, masterSecret, recipientDevice, keyExchangeMessage); + RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), + recipientDeviceId); + KeyExchangeProcessor processor = new KeyExchangeProcessor(ReceiveKeyActivity.this, + masterSecret, recipientDevice); + processor.processKeyExchangeMessage(keyExchangeMessage, threadId); + DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this) .markAsProcessedKeyExchange(messageId); } catch (InvalidMessageException e) { @@ -240,7 +236,7 @@ public class ReceiveKeyActivity extends Activity { } else if (keyExchangeMessageBundle != null) { try { RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId); - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(ReceiveKeyActivity.this, + KeyExchangeProcessor processor = new KeyExchangeProcessor(ReceiveKeyActivity.this, masterSecret, recipientDevice); processor.processKeyExchangeMessage(keyExchangeMessageBundle); diff --git a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java index f55b77b901..deb4c061b2 100644 --- a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java +++ b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java @@ -41,7 +41,6 @@ import org.thoughtcrime.securesms.service.SendReceiveService; 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; @@ -417,22 +416,20 @@ public class DecryptingQueue { database.updateMessageBody(masterSecret, messageId, plaintextBody); MessageNotifier.updateNotification(context, masterSecret); - } catch (InvalidMessageException ime) { + } catch (InvalidMessageException | IOException ime) { Log.w("DecryptionQueue", ime); database.markAsDecryptFailed(messageId); - } catch (IOException e) { - Log.w("DecryptionQueue", e); - database.markAsDecryptFailed(messageId); } } private void handleKeyExchangeProcessing(String plaintextBody) { if (TextSecurePreferences.isAutoRespondKeyExchangeEnabled(context)) { try { - Recipient recipient = RecipientFactory.getRecipientsFromString(context, originator, false).getPrimaryRecipient(); + Recipient recipient = RecipientFactory.getRecipientsFromString(context, originator, false) + .getPrimaryRecipient(); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), deviceId); - KeyExchangeMessage message = KeyExchangeMessage.createFor(plaintextBody); - KeyExchangeProcessor processor = KeyExchangeProcessor.createFor(context, masterSecret, recipientDevice, message); + KeyExchangeMessage message = new KeyExchangeMessage(plaintextBody); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice); if (processor.isStale(message)) { DatabaseFactory.getEncryptingSmsDatabase(context).markAsStaleKeyExchange(messageId); @@ -443,13 +440,7 @@ public class DecryptingQueue { } catch (InvalidVersionException e) { Log.w("DecryptingQueue", e); DatabaseFactory.getEncryptingSmsDatabase(context).markAsInvalidVersionKeyExchange(messageId); - } catch (InvalidKeyException e) { - Log.w("DecryptingQueue", e); - DatabaseFactory.getEncryptingSmsDatabase(context).markAsCorruptKeyExchange(messageId); - } catch (InvalidMessageException e) { - Log.w("DecryptingQueue", e); - DatabaseFactory.getEncryptingSmsDatabase(context).markAsCorruptKeyExchange(messageId); - } catch (RecipientFormattingException e) { + } catch (InvalidMessageException | RecipientFormattingException e) { Log.w("DecryptingQueue", e); DatabaseFactory.getEncryptingSmsDatabase(context).markAsCorruptKeyExchange(messageId); } catch (LegacyMessageException e) { diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java index 24abec36fe..ceb2dcd0f6 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java @@ -22,7 +22,7 @@ import android.content.Context; import android.content.DialogInterface; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessageV2; +import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; @@ -62,12 +62,12 @@ public class KeyExchangeInitiator { private static void initiateKeyExchange(Context context, MasterSecret masterSecret, Recipient recipient) { int sequence = getRandomSequence(); - int flags = KeyExchangeMessageV2.INITIATE_FLAG; + int flags = KeyExchangeMessage.INITIATE_FLAG; ECKeyPair baseKey = Curve.generateKeyPair(true); ECKeyPair ephemeralKey = Curve.generateKeyPair(true); IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - KeyExchangeMessageV2 message = new KeyExchangeMessageV2(sequence, flags, + KeyExchangeMessage message = new KeyExchangeMessage(sequence, flags, baseKey.getPublicKey(), ephemeralKey.getPublicKey(), identityKey.getPublicKey()); diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java index 165e957260..eeec9cf1ee 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessor.java @@ -1,45 +1,254 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ package org.thoughtcrime.securesms.crypto; import android.content.Context; import android.content.Intent; +import android.util.Log; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.service.KeyCachingService; +import org.thoughtcrime.securesms.service.PreKeyService; +import org.thoughtcrime.securesms.sms.MessageSender; +import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; +import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libaxolotl.IdentityKey; +import org.whispersystems.libaxolotl.IdentityKeyPair; +import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECKeyPair; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; +import org.whispersystems.libaxolotl.ratchet.RatchetingSession; +import org.whispersystems.libaxolotl.state.SessionRecord; +import org.whispersystems.libaxolotl.state.SessionStore; import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.push.PreKeyEntity; +import org.whispersystems.textsecure.storage.InvalidKeyIdException; +import org.whispersystems.textsecure.storage.PreKeyRecord; import org.whispersystems.textsecure.storage.RecipientDevice; +import org.whispersystems.textsecure.storage.TextSecureSessionStore; +import org.whispersystems.textsecure.util.Medium; -public abstract class KeyExchangeProcessor { +/** + * This class processes key exchange interactions. + * + * @author Moxie Marlinspike + */ + +public class KeyExchangeProcessor { public static final String SECURITY_UPDATE_EVENT = "org.thoughtcrime.securesms.KEY_EXCHANGE_UPDATE"; - public abstract boolean isStale(KeyExchangeMessage message); - public abstract boolean isTrusted(KeyExchangeMessage message); - public abstract void processKeyExchangeMessage(KeyExchangeMessage message, long threadid) - throws InvalidMessageException; + private Context context; + private RecipientDevice recipientDevice; + private MasterSecret masterSecret; + private SessionStore sessionStore; - public static KeyExchangeProcessor createFor(Context context, MasterSecret masterSecret, - RecipientDevice recipientDevice, - KeyExchangeMessage message) + public KeyExchangeProcessor(Context context, MasterSecret masterSecret, RecipientDevice recipientDevice) { - return new KeyExchangeProcessorV2(context, masterSecret, recipientDevice); + this.context = context; + this.recipientDevice = recipientDevice; + this.masterSecret = masterSecret; + this.sessionStore = new TextSecureSessionStore(context, masterSecret); + } + + public boolean isTrusted(PreKeyWhisperMessage message) { + return isTrusted(message.getIdentityKey()); + } + + public boolean isTrusted(PreKeyEntity entity) { + return isTrusted(entity.getIdentityKey()); + } + + public boolean isTrusted(KeyExchangeMessage message) { + return message.hasIdentityKey() && isTrusted(message.getIdentityKey()); + } + + public boolean isTrusted(IdentityKey identityKey) { + return DatabaseFactory.getIdentityDatabase(context).isValidIdentity(masterSecret, + recipientDevice.getRecipientId(), + identityKey); + } + + public boolean isStale(KeyExchangeMessage message) { + SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), + recipientDevice.getDeviceId()); + + return + message.isResponse() && + (!sessionRecord.getSessionState().hasPendingKeyExchange() || + sessionRecord.getSessionState().getPendingKeyExchangeSequence() != message.getSequence()) && + !message.isResponseForSimultaneousInitiate(); + } + + public void processKeyExchangeMessage(PreKeyWhisperMessage message) + throws InvalidKeyIdException, InvalidKeyException + { + int preKeyId = message.getPreKeyId(); + ECPublicKey theirBaseKey = message.getBaseKey(); + ECPublicKey theirEphemeralKey = message.getWhisperMessage().getSenderEphemeral(); + IdentityKey theirIdentityKey = message.getIdentityKey(); + + Log.w("KeyExchangeProcessor", "Received pre-key with local key ID: " + preKeyId); + + if (!PreKeyRecord.hasRecord(context, preKeyId) && + sessionStore.contains(recipientDevice.getRecipientId(), recipientDevice.getDeviceId())) + { + Log.w("KeyExchangeProcessor", "We've already processed the prekey part, letting bundled message fall through..."); + return; + } + + if (!PreKeyRecord.hasRecord(context, preKeyId)) + throw new InvalidKeyIdException("No such prekey: " + preKeyId); + + SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), + recipientDevice.getDeviceId()); + PreKeyRecord preKeyRecord = new PreKeyRecord(context, masterSecret, preKeyId); + ECKeyPair ourBaseKey = preKeyRecord.getKeyPair(); + ECKeyPair ourEphemeralKey = ourBaseKey; + IdentityKeyPair ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); + boolean simultaneousInitiate = sessionRecord.getSessionState().hasPendingPreKey(); + + if (!simultaneousInitiate) sessionRecord.reset(); + else sessionRecord.archiveCurrentState(); + + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + ourBaseKey, theirBaseKey, + ourEphemeralKey, theirEphemeralKey, + ourIdentityKey, theirIdentityKey); + + sessionRecord.getSessionState().setLocalRegistrationId(TextSecurePreferences.getLocalRegistrationId(context)); + sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); + + if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true); + + sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); + + if (preKeyId != Medium.MAX_VALUE) { + PreKeyRecord.delete(context, preKeyId); + } + + PreKeyService.initiateRefresh(context, masterSecret); + + DatabaseFactory.getIdentityDatabase(context) + .saveIdentity(masterSecret, recipientDevice.getRecipientId(), theirIdentityKey); + } + + public void processKeyExchangeMessage(PreKeyEntity message, long threadId) + throws InvalidKeyException + { + SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), + recipientDevice.getDeviceId()); + ECKeyPair ourBaseKey = Curve.generateKeyPair(true); + ECKeyPair ourEphemeralKey = Curve.generateKeyPair(true); + ECPublicKey theirBaseKey = message.getPublicKey(); + ECPublicKey theirEphemeralKey = theirBaseKey; + IdentityKey theirIdentityKey = message.getIdentityKey(); + IdentityKeyPair ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); + + if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState(); + else sessionRecord.reset(); + + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + ourBaseKey, theirBaseKey, ourEphemeralKey, + theirEphemeralKey, ourIdentityKey, theirIdentityKey); + + sessionRecord.getSessionState().setPendingPreKey(message.getKeyId(), ourBaseKey.getPublicKey()); + sessionRecord.getSessionState().setLocalRegistrationId(TextSecurePreferences.getLocalRegistrationId(context)); + sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); + + sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); + + DatabaseFactory.getIdentityDatabase(context) + .saveIdentity(masterSecret, recipientDevice.getRecipientId(), message.getIdentityKey()); + + if (threadId != -1) { + broadcastSecurityUpdateEvent(context, threadId); + } + } + + public void processKeyExchangeMessage(KeyExchangeMessage message, long threadId) + throws InvalidMessageException + { + try { + SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), + recipientDevice.getDeviceId()); + Recipient recipient = RecipientFactory.getRecipientsForIds(context, + String.valueOf(recipientDevice.getRecipientId()), + false) + .getPrimaryRecipient(); + + Log.w("KeyExchangeProcessor", "Received key exchange with sequence: " + message.getSequence()); + + if (message.isInitiate()) { + ECKeyPair ourBaseKey, ourEphemeralKey; + IdentityKeyPair ourIdentityKey; + + int flags = KeyExchangeMessage.RESPONSE_FLAG; + + Log.w("KeyExchangeProcessor", "KeyExchange is an initiate."); + + if (!sessionRecord.getSessionState().hasPendingKeyExchange()) { + Log.w("KeyExchangeProcessor", "We don't have a pending initiate..."); + ourBaseKey = Curve.generateKeyPair(true); + ourEphemeralKey = Curve.generateKeyPair(true); + ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); + + sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey, + ourEphemeralKey, ourIdentityKey); + } else { + Log.w("KeyExchangeProcessor", "We alredy have a pending initiate, responding as simultaneous initiate..."); + ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey(); + ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey(); + ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey(); + flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG; + + sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey, + ourEphemeralKey, ourIdentityKey); + } + + KeyExchangeMessage ourMessage = new KeyExchangeMessage(message.getSequence(), + flags, ourBaseKey.getPublicKey(), + ourEphemeralKey.getPublicKey(), + ourIdentityKey.getPublicKey()); + + OutgoingKeyExchangeMessage textMessage = new OutgoingKeyExchangeMessage(recipient, + ourMessage.serialize()); + MessageSender.send(context, masterSecret, textMessage, threadId, true); + } + + if (message.getSequence() != sessionRecord.getSessionState().getPendingKeyExchangeSequence()) { + Log.w("KeyExchangeProcessor", "No matching sequence for response. " + + "Is simultaneous initiate response: " + message.isResponseForSimultaneousInitiate()); + return; + } + + ECKeyPair ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey(); + ECKeyPair ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey(); + IdentityKeyPair ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey(); + + sessionRecord.reset(); + + RatchetingSession.initializeSession(sessionRecord.getSessionState(), + ourBaseKey, message.getBaseKey(), + ourEphemeralKey, message.getEphemeralKey(), + ourIdentityKey, message.getIdentityKey()); + + sessionRecord.getSessionState().setSessionVersion(message.getVersion()); + sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); + + DatabaseFactory.getIdentityDatabase(context) + .saveIdentity(masterSecret, recipientDevice.getRecipientId(), message.getIdentityKey()); + + DecryptingQueue.scheduleRogueMessages(context, masterSecret, recipient); + + broadcastSecurityUpdateEvent(context, threadId); + } catch (InvalidKeyException e) { + throw new InvalidMessageException(e); + } } public static void broadcastSecurityUpdateEvent(Context context, long threadId) { @@ -49,4 +258,4 @@ public abstract class KeyExchangeProcessor { context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION); } -} \ No newline at end of file +} diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java deleted file mode 100644 index ab030a8857..0000000000 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java +++ /dev/null @@ -1,254 +0,0 @@ -package org.thoughtcrime.securesms.crypto; - -import android.content.Context; -import android.util.Log; - -import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; -import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessageV2; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientFactory; -import org.thoughtcrime.securesms.service.PreKeyService; -import org.thoughtcrime.securesms.sms.MessageSender; -import org.thoughtcrime.securesms.sms.OutgoingKeyExchangeMessage; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libaxolotl.IdentityKey; -import org.whispersystems.libaxolotl.IdentityKeyPair; -import org.whispersystems.libaxolotl.InvalidKeyException; -import org.whispersystems.libaxolotl.InvalidMessageException; -import org.whispersystems.libaxolotl.ecc.Curve; -import org.whispersystems.libaxolotl.ecc.ECKeyPair; -import org.whispersystems.libaxolotl.ecc.ECPublicKey; -import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; -import org.whispersystems.libaxolotl.ratchet.RatchetingSession; -import org.whispersystems.libaxolotl.state.SessionRecord; -import org.whispersystems.libaxolotl.state.SessionStore; -import org.whispersystems.textsecure.crypto.MasterSecret; -import org.whispersystems.textsecure.push.PreKeyEntity; -import org.whispersystems.textsecure.storage.InvalidKeyIdException; -import org.whispersystems.textsecure.storage.PreKeyRecord; -import org.whispersystems.textsecure.storage.RecipientDevice; -import org.whispersystems.textsecure.storage.TextSecureSessionStore; -import org.whispersystems.textsecure.util.Medium; - -/** - * This class processes key exchange interactions. - * - * @author Moxie Marlinspike - */ - -public class KeyExchangeProcessorV2 extends KeyExchangeProcessor { - - private Context context; - private RecipientDevice recipientDevice; - private MasterSecret masterSecret; - private SessionStore sessionStore; - - public KeyExchangeProcessorV2(Context context, MasterSecret masterSecret, RecipientDevice recipientDevice) - { - this.context = context; - this.recipientDevice = recipientDevice; - this.masterSecret = masterSecret; - this.sessionStore = new TextSecureSessionStore(context, masterSecret); - } - - public boolean isTrusted(PreKeyWhisperMessage message) { - return isTrusted(message.getIdentityKey()); - } - - public boolean isTrusted(PreKeyEntity entity) { - return isTrusted(entity.getIdentityKey()); - } - - public boolean isTrusted(KeyExchangeMessage message) { - return message.hasIdentityKey() && isTrusted(message.getIdentityKey()); - } - - public boolean isTrusted(IdentityKey identityKey) { - return DatabaseFactory.getIdentityDatabase(context).isValidIdentity(masterSecret, - recipientDevice.getRecipientId(), - identityKey); - } - - public boolean isStale(KeyExchangeMessage m) { - KeyExchangeMessageV2 message = (KeyExchangeMessageV2) m; - SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), - recipientDevice.getDeviceId()); - - return - message.isResponse() && - (!sessionRecord.getSessionState().hasPendingKeyExchange() || - sessionRecord.getSessionState().getPendingKeyExchangeSequence() != message.getSequence()) && - !message.isResponseForSimultaneousInitiate(); - } - - public void processKeyExchangeMessage(PreKeyWhisperMessage message) - throws InvalidKeyIdException, InvalidKeyException - { - int preKeyId = message.getPreKeyId(); - ECPublicKey theirBaseKey = message.getBaseKey(); - ECPublicKey theirEphemeralKey = message.getWhisperMessage().getSenderEphemeral(); - IdentityKey theirIdentityKey = message.getIdentityKey(); - - Log.w("KeyExchangeProcessor", "Received pre-key with local key ID: " + preKeyId); - - if (!PreKeyRecord.hasRecord(context, preKeyId) && - sessionStore.contains(recipientDevice.getRecipientId(), recipientDevice.getDeviceId())) - { - Log.w("KeyExchangeProcessor", "We've already processed the prekey part, letting bundled message fall through..."); - return; - } - - if (!PreKeyRecord.hasRecord(context, preKeyId)) - throw new InvalidKeyIdException("No such prekey: " + preKeyId); - - SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), - recipientDevice.getDeviceId()); - PreKeyRecord preKeyRecord = new PreKeyRecord(context, masterSecret, preKeyId); - ECKeyPair ourBaseKey = preKeyRecord.getKeyPair(); - ECKeyPair ourEphemeralKey = ourBaseKey; - IdentityKeyPair ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - boolean simultaneousInitiate = sessionRecord.getSessionState().hasPendingPreKey(); - - if (!simultaneousInitiate) sessionRecord.reset(); - else sessionRecord.archiveCurrentState(); - - RatchetingSession.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, - ourEphemeralKey, theirEphemeralKey, - ourIdentityKey, theirIdentityKey); - - sessionRecord.getSessionState().setLocalRegistrationId(TextSecurePreferences.getLocalRegistrationId(context)); - sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); - - if (simultaneousInitiate) sessionRecord.getSessionState().setNeedsRefresh(true); - - sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); - - if (preKeyId != Medium.MAX_VALUE) { - PreKeyRecord.delete(context, preKeyId); - } - - PreKeyService.initiateRefresh(context, masterSecret); - - DatabaseFactory.getIdentityDatabase(context) - .saveIdentity(masterSecret, recipientDevice.getRecipientId(), theirIdentityKey); - } - - public void processKeyExchangeMessage(PreKeyEntity message, long threadId) - throws InvalidKeyException - { - SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), - recipientDevice.getDeviceId()); - ECKeyPair ourBaseKey = Curve.generateKeyPair(true); - ECKeyPair ourEphemeralKey = Curve.generateKeyPair(true); - ECPublicKey theirBaseKey = message.getPublicKey(); - ECPublicKey theirEphemeralKey = theirBaseKey; - IdentityKey theirIdentityKey = message.getIdentityKey(); - IdentityKeyPair ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - - if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState(); - else sessionRecord.reset(); - - RatchetingSession.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, theirBaseKey, ourEphemeralKey, - theirEphemeralKey, ourIdentityKey, theirIdentityKey); - - sessionRecord.getSessionState().setPendingPreKey(message.getKeyId(), ourBaseKey.getPublicKey()); - sessionRecord.getSessionState().setLocalRegistrationId(TextSecurePreferences.getLocalRegistrationId(context)); - sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId()); - - sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); - - DatabaseFactory.getIdentityDatabase(context) - .saveIdentity(masterSecret, recipientDevice.getRecipientId(), message.getIdentityKey()); - - if (threadId != -1) { - broadcastSecurityUpdateEvent(context, threadId); - } - } - - @Override - public void processKeyExchangeMessage(KeyExchangeMessage _message, long threadId) - throws InvalidMessageException - { - try { - KeyExchangeMessageV2 message = (KeyExchangeMessageV2) _message; - SessionRecord sessionRecord = sessionStore.get(recipientDevice.getRecipientId(), - recipientDevice.getDeviceId()); - Recipient recipient = RecipientFactory.getRecipientsForIds(context, - String.valueOf(recipientDevice.getRecipientId()), - false) - .getPrimaryRecipient(); - - Log.w("KeyExchangeProcessorV2", "Received key exchange with sequence: " + message.getSequence()); - - if (message.isInitiate()) { - ECKeyPair ourBaseKey, ourEphemeralKey; - IdentityKeyPair ourIdentityKey; - - int flags = KeyExchangeMessageV2.RESPONSE_FLAG; - - Log.w("KeyExchangeProcessorV2", "KeyExchange is an initiate."); - - if (!sessionRecord.getSessionState().hasPendingKeyExchange()) { - Log.w("KeyExchangeProcessorV2", "We don't have a pending initiate..."); - ourBaseKey = Curve.generateKeyPair(true); - ourEphemeralKey = Curve.generateKeyPair(true); - ourIdentityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret); - - sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey, - ourEphemeralKey, ourIdentityKey); - } else { - Log.w("KeyExchangeProcessorV2", "We alredy have a pending initiate, responding as simultaneous initiate..."); - ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey(); - ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey(); - ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey(); - flags |= KeyExchangeMessageV2.SIMULTAENOUS_INITIATE_FLAG; - - sessionRecord.getSessionState().setPendingKeyExchange(message.getSequence(), ourBaseKey, - ourEphemeralKey, ourIdentityKey); - } - - KeyExchangeMessageV2 ourMessage = new KeyExchangeMessageV2(message.getSequence(), - flags, ourBaseKey.getPublicKey(), - ourEphemeralKey.getPublicKey(), - ourIdentityKey.getPublicKey()); - - OutgoingKeyExchangeMessage textMessage = new OutgoingKeyExchangeMessage(recipient, - ourMessage.serialize()); - MessageSender.send(context, masterSecret, textMessage, threadId, false); - } - - if (message.getSequence() != sessionRecord.getSessionState().getPendingKeyExchangeSequence()) { - Log.w("KeyExchangeProcessorV2", "No matching sequence for response. " + - "Is simultaneous initiate response: " + message.isResponseForSimultaneousInitiate()); - return; - } - - ECKeyPair ourBaseKey = sessionRecord.getSessionState().getPendingKeyExchangeBaseKey(); - ECKeyPair ourEphemeralKey = sessionRecord.getSessionState().getPendingKeyExchangeEphemeralKey(); - IdentityKeyPair ourIdentityKey = sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey(); - - sessionRecord.reset(); - - RatchetingSession.initializeSession(sessionRecord.getSessionState(), - ourBaseKey, message.getBaseKey(), - ourEphemeralKey, message.getEphemeralKey(), - ourIdentityKey, message.getIdentityKey()); - - sessionRecord.getSessionState().setSessionVersion(message.getVersion()); - sessionStore.put(recipientDevice.getRecipientId(), recipientDevice.getDeviceId(), sessionRecord); - - DatabaseFactory.getIdentityDatabase(context) - .saveIdentity(masterSecret, recipientDevice.getRecipientId(), message.getIdentityKey()); - - DecryptingQueue.scheduleRogueMessages(context, masterSecret, recipient); - - broadcastSecurityUpdateEvent(context, threadId); - } catch (InvalidKeyException e) { - throw new InvalidMessageException(e); - } - } - -} diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java index beef2064ec..c2a79cd840 100644 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java +++ b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessage.java @@ -1,38 +1,144 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ package org.thoughtcrime.securesms.crypto.protocol; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; 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.ecc.Curve; +import org.whispersystems.libaxolotl.ecc.ECPublicKey; +import org.whispersystems.libaxolotl.protocol.CiphertextMessage; +import org.whispersystems.libaxolotl.protocol.WhisperProtos; +import org.whispersystems.textsecure.util.Base64; +import org.whispersystems.textsecure.util.Conversions; +import org.whispersystems.textsecure.util.Util; -public abstract class KeyExchangeMessage { - public abstract IdentityKey getIdentityKey(); - public abstract boolean hasIdentityKey(); - public abstract int getMaxVersion(); - public abstract int getVersion(); +import java.io.IOException; - public static KeyExchangeMessage createFor(String rawMessage) - throws InvalidMessageException, InvalidKeyException, InvalidVersionException, LegacyMessageException +public class KeyExchangeMessage { + + public static final int INITIATE_FLAG = 0x01; + public static final int RESPONSE_FLAG = 0X02; + public static final int SIMULTAENOUS_INITIATE_FLAG = 0x04; + + private final int version; + private final int supportedVersion; + private final int sequence; + private final int flags; + + private final ECPublicKey baseKey; + private final ECPublicKey ephemeralKey; + private final IdentityKey identityKey; + private final byte[] serialized; + + public KeyExchangeMessage(int sequence, int flags, + ECPublicKey baseKey, ECPublicKey ephemeralKey, + IdentityKey identityKey) { - return new KeyExchangeMessageV2(rawMessage); + this.supportedVersion = CiphertextMessage.CURRENT_VERSION; + this.version = CiphertextMessage.CURRENT_VERSION; + this.sequence = sequence; + this.flags = flags; + this.baseKey = baseKey; + this.ephemeralKey = ephemeralKey; + this.identityKey = identityKey; + + byte[] version = {Conversions.intsToByteHighAndLow(this.version, this.supportedVersion)}; + byte[] message = WhisperProtos.KeyExchangeMessage.newBuilder() + .setId((sequence << 5) | flags) + .setBaseKey(ByteString.copyFrom(baseKey.serialize())) + .setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize())) + .setIdentityKey(ByteString.copyFrom(identityKey.serialize())) + .build().toByteArray(); + + this.serialized = Util.combine(version, message); } -} \ No newline at end of file + + public KeyExchangeMessage(String serializedAndEncoded) + throws InvalidMessageException, InvalidVersionException, LegacyMessageException + { + try { + byte[] serialized = Base64.decodeWithoutPadding(serializedAndEncoded); + byte[][] parts = Util.split(serialized, 1, serialized.length - 1); + + this.version = Conversions.highBitsToInt(parts[0][0]); + this.supportedVersion = Conversions.lowBitsToInt(parts[0][0]); + + if (this.version <= CiphertextMessage.UNSUPPORTED_VERSION) { + throw new LegacyMessageException("Unsupported legacy version: " + this.version); + } + + if (this.version > CiphertextMessage.CURRENT_VERSION) { + throw new InvalidVersionException("Unknown version: " + this.version); + } + + WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]); + + if (!message.hasId() || !message.hasBaseKey() || + !message.hasEphemeralKey() || !message.hasIdentityKey()) + { + throw new InvalidMessageException("Some required fields missing!"); + } + + this.sequence = message.getId() >> 5; + this.flags = message.getId() & 0x1f; + this.serialized = serialized; + this.baseKey = Curve.decodePoint(message.getBaseKey().toByteArray(), 0); + this.ephemeralKey = Curve.decodePoint(message.getEphemeralKey().toByteArray(), 0); + this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0); + } catch (InvalidKeyException | IOException e) { + throw new InvalidMessageException(e); + } + } + + public int getVersion() { + return version; + } + + public ECPublicKey getBaseKey() { + return baseKey; + } + + public ECPublicKey getEphemeralKey() { + return ephemeralKey; + } + + public IdentityKey getIdentityKey() { + return identityKey; + } + + public boolean hasIdentityKey() { + return true; + } + + public int getMaxVersion() { + return supportedVersion; + } + + public boolean isResponse() { + return ((flags & RESPONSE_FLAG) != 0); + } + + public boolean isInitiate() { + return (flags & INITIATE_FLAG) != 0; + } + + public boolean isResponseForSimultaneousInitiate() { + return (flags & SIMULTAENOUS_INITIATE_FLAG) != 0; + } + + public int getFlags() { + return flags; + } + + public int getSequence() { + return sequence; + } + + public String serialize() { + return Base64.encodeBytesWithoutPadding(serialized); + } +} diff --git a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java b/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java deleted file mode 100644 index c8b74459f0..0000000000 --- a/src/org/thoughtcrime/securesms/crypto/protocol/KeyExchangeMessageV2.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.thoughtcrime.securesms.crypto.protocol; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - -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.ecc.Curve; -import org.whispersystems.libaxolotl.ecc.ECPublicKey; -import org.whispersystems.libaxolotl.protocol.CiphertextMessage; -import org.whispersystems.libaxolotl.protocol.WhisperProtos; -import org.whispersystems.textsecure.util.Base64; -import org.whispersystems.textsecure.util.Conversions; -import org.whispersystems.textsecure.util.Util; - -import java.io.IOException; - -public class KeyExchangeMessageV2 extends KeyExchangeMessage { - - public static final int INITIATE_FLAG = 0x01; - public static final int RESPONSE_FLAG = 0X02; - public static final int SIMULTAENOUS_INITIATE_FLAG = 0x04; - - private final int version; - private final int supportedVersion; - private final int sequence; - private final int flags; - - private final ECPublicKey baseKey; - private final ECPublicKey ephemeralKey; - private final IdentityKey identityKey; - private final byte[] serialized; - - public KeyExchangeMessageV2(int sequence, int flags, - ECPublicKey baseKey, ECPublicKey ephemeralKey, - IdentityKey identityKey) - { - this.supportedVersion = CiphertextMessage.CURRENT_VERSION; - this.version = CiphertextMessage.CURRENT_VERSION; - this.sequence = sequence; - this.flags = flags; - this.baseKey = baseKey; - this.ephemeralKey = ephemeralKey; - this.identityKey = identityKey; - - byte[] version = {Conversions.intsToByteHighAndLow(this.version, this.supportedVersion)}; - byte[] message = WhisperProtos.KeyExchangeMessage.newBuilder() - .setId((sequence << 5) | flags) - .setBaseKey(ByteString.copyFrom(baseKey.serialize())) - .setEphemeralKey(ByteString.copyFrom(ephemeralKey.serialize())) - .setIdentityKey(ByteString.copyFrom(identityKey.serialize())) - .build().toByteArray(); - - this.serialized = Util.combine(version, message); - } - - public KeyExchangeMessageV2(String serializedAndEncoded) - throws InvalidMessageException, InvalidVersionException, LegacyMessageException - { - try { - byte[] serialized = Base64.decodeWithoutPadding(serializedAndEncoded); - byte[][] parts = Util.split(serialized, 1, serialized.length - 1); - - this.version = Conversions.highBitsToInt(parts[0][0]); - this.supportedVersion = Conversions.lowBitsToInt(parts[0][0]); - - if (this.version <= CiphertextMessage.UNSUPPORTED_VERSION) { - throw new LegacyMessageException("Unsupported legacy version: " + this.version); - } - - if (this.version > CiphertextMessage.CURRENT_VERSION) { - throw new InvalidVersionException("Unknown version: " + this.version); - } - - WhisperProtos.KeyExchangeMessage message = WhisperProtos.KeyExchangeMessage.parseFrom(parts[1]); - - if (!message.hasId() || !message.hasBaseKey() || - !message.hasEphemeralKey() || !message.hasIdentityKey()) - { - throw new InvalidMessageException("Some required fields missing!"); - } - - this.sequence = message.getId() >> 5; - this.flags = message.getId() & 0x1f; - this.serialized = serialized; - this.baseKey = Curve.decodePoint(message.getBaseKey().toByteArray(), 0); - this.ephemeralKey = Curve.decodePoint(message.getEphemeralKey().toByteArray(), 0); - this.identityKey = new IdentityKey(message.getIdentityKey().toByteArray(), 0); - } catch (InvalidProtocolBufferException e) { - throw new InvalidMessageException(e); - } catch (InvalidKeyException e) { - throw new InvalidMessageException(e); - } catch (IOException e) { - throw new InvalidMessageException(e); - } - } - - @Override - public int getVersion() { - return version; - } - - public ECPublicKey getBaseKey() { - return baseKey; - } - - public ECPublicKey getEphemeralKey() { - return ephemeralKey; - } - - @Override - public IdentityKey getIdentityKey() { - return identityKey; - } - - @Override - public boolean hasIdentityKey() { - return true; - } - - @Override - public int getMaxVersion() { - return supportedVersion; - } - - public boolean isResponse() { - return ((flags & RESPONSE_FLAG) != 0); - } - - public boolean isInitiate() { - return (flags & INITIATE_FLAG) != 0; - } - - public boolean isResponseForSimultaneousInitiate() { - return (flags & SIMULTAENOUS_INITIATE_FLAG) != 0; - } - - public int getFlags() { - return flags; - } - - public int getSequence() { - return sequence; - } - - public String serialize() { - return Base64.encodeBytesWithoutPadding(serialized); - } -} diff --git a/src/org/thoughtcrime/securesms/service/PushReceiver.java b/src/org/thoughtcrime/securesms/service/PushReceiver.java index c0675d6be9..e9733f8fbd 100644 --- a/src/org/thoughtcrime/securesms/service/PushReceiver.java +++ b/src/org/thoughtcrime/securesms/service/PushReceiver.java @@ -9,7 +9,6 @@ import com.google.protobuf.InvalidProtocolBufferException; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; -import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; @@ -115,7 +114,7 @@ public class PushReceiver { try { Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSource(), false).getPrimaryRecipient(); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSourceDevice()); - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, recipientDevice); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice); PreKeyWhisperMessage preKeyExchange = new PreKeyWhisperMessage(message.getBody()); if (processor.isTrusted(preKeyExchange)) { diff --git a/src/org/thoughtcrime/securesms/service/SmsReceiver.java b/src/org/thoughtcrime/securesms/service/SmsReceiver.java index 8b5cda76c2..2943255242 100644 --- a/src/org/thoughtcrime/securesms/service/SmsReceiver.java +++ b/src/org/thoughtcrime/securesms/service/SmsReceiver.java @@ -23,7 +23,6 @@ import android.util.Pair; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; -import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.crypto.protocol.KeyExchangeMessage; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -114,7 +113,7 @@ public class SmsReceiver { try { Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSender(), false).getPrimaryRecipient(); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSenderDeviceId()); - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, recipientDevice); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice); SmsTransportDetails transportDetails = new SmsTransportDetails(); byte[] rawMessage = transportDetails.getDecodedMessage(message.getMessageBody().getBytes()); PreKeyWhisperMessage preKeyExchange = new PreKeyWhisperMessage(rawMessage); @@ -127,7 +126,7 @@ public class SmsReceiver { IncomingEncryptedMessage bundledMessage = new IncomingEncryptedMessage(message, bundledMessageBody); Pair messageAndThreadId = storeSecureMessage(masterSecret, bundledMessage); - Intent intent = new Intent(KeyExchangeProcessorV2.SECURITY_UPDATE_EVENT); + Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT); intent.putExtra("thread_id", messageAndThreadId.second); intent.setPackage(context.getPackageName()); context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION); @@ -164,8 +163,8 @@ public class SmsReceiver { try { Recipient recipient = RecipientFactory.getRecipientsFromString(context, message.getSender(), false).getPrimaryRecipient(); RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), message.getSenderDeviceId()); - KeyExchangeMessage exchangeMessage = KeyExchangeMessage.createFor(message.getMessageBody()); - KeyExchangeProcessor processor = KeyExchangeProcessor.createFor(context, masterSecret, recipientDevice, exchangeMessage); + KeyExchangeMessage exchangeMessage = new KeyExchangeMessage(message.getMessageBody()); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipientDevice); if (processor.isStale(exchangeMessage)) { message.setStale(true); @@ -180,13 +179,7 @@ public class SmsReceiver { } catch (InvalidVersionException e) { Log.w("SmsReceiver", e); message.setInvalidVersion(true); - } catch (InvalidKeyException e) { - Log.w("SmsReceiver", e); - message.setCorrupted(true); - } catch (InvalidMessageException e) { - Log.w("SmsReceiver", e); - message.setCorrupted(true); - } catch (RecipientFormattingException e) { + } catch (InvalidMessageException | RecipientFormattingException e) { Log.w("SmsReceiver", e); message.setCorrupted(true); } catch (LegacyMessageException e) { diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index 25a3950b89..39cb282286 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -23,7 +23,6 @@ import android.util.Log; import com.google.protobuf.ByteString; import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor; -import org.thoughtcrime.securesms.crypto.KeyExchangeProcessorV2; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.model.SmsMessageRecord; @@ -212,7 +211,7 @@ public class PushTransport extends BaseTransport { for (int missingDeviceId : mismatchedDevices.getMissingDevices()) { PushAddress address = PushAddress.create(context, recipientId, e164number, missingDeviceId); PreKeyEntity preKey = socket.getPreKey(address); - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, address); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, address); if (processor.isTrusted(preKey)) { processor.processKeyExchangeMessage(preKey, threadId); @@ -331,7 +330,7 @@ public class PushTransport extends BaseTransport { for (PreKeyEntity preKey : preKeys) { PushAddress device = PushAddress.create(context, pushAddress.getRecipientId(), pushAddress.getNumber(), preKey.getDeviceId()); - KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, device); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, device); if (processor.isTrusted(preKey)) { processor.processKeyExchangeMessage(preKey, threadId);