aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java')
-rw-r--r--src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java80
1 files changed, 54 insertions, 26 deletions
diff --git a/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java b/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java
index cbfdaf28e..71e20676e 100644
--- a/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java
+++ b/src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java
@@ -2,6 +2,7 @@ package de.pixart.messenger.crypto.axolotl;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.util.Log;
import org.whispersystems.libsignal.DuplicateMessageException;
import org.whispersystems.libsignal.IdentityKey;
@@ -19,6 +20,10 @@ import org.whispersystems.libsignal.protocol.PreKeySignalMessage;
import org.whispersystems.libsignal.protocol.SignalMessage;
import org.whispersystems.libsignal.util.guava.Optional;
+import java.util.Iterator;
+import java.util.List;
+
+import de.pixart.messenger.Config;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.utils.CryptoHelper;
@@ -79,35 +84,56 @@ public class XmppAxolotlSession implements Comparable<XmppAxolotlSession> {
}
@Nullable
- byte[] processReceiving(AxolotlKey encryptedKey) throws CryptoFailedException {
- byte[] plaintext;
+ byte[] processReceiving(List<AxolotlKey> possibleKeys) throws CryptoFailedException {
+ byte[] plaintext = null;
FingerprintStatus status = getTrust();
if (!status.isCompromised()) {
- try {
- if (encryptedKey.prekey) {
- PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(encryptedKey.key);
- Optional<Integer> optionalPreKeyId = preKeySignalMessage.getPreKeyId();
- IdentityKey identityKey = preKeySignalMessage.getIdentityKey();
- if (!optionalPreKeyId.isPresent()) {
- throw new CryptoFailedException("PreKeyWhisperMessage did not contain a PreKeyId");
+ Iterator<AxolotlKey> iterator = possibleKeys.iterator();
+ while (iterator.hasNext()) {
+ AxolotlKey encryptedKey = iterator.next();
+ try {
+ if (encryptedKey.prekey) {
+ PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(encryptedKey.key);
+ Optional<Integer> optionalPreKeyId = preKeySignalMessage.getPreKeyId();
+ IdentityKey identityKey = preKeySignalMessage.getIdentityKey();
+ if (!optionalPreKeyId.isPresent()) {
+ if (iterator.hasNext()) {
+ continue;
+ }
+ throw new CryptoFailedException("PreKeyWhisperMessage did not contain a PreKeyId");
+ }
+ preKeyId = optionalPreKeyId.get();
+ if (this.identityKey != null && !this.identityKey.equals(identityKey)) {
+ if (iterator.hasNext()) {
+ continue;
+ }
+ throw new CryptoFailedException("Received PreKeyWhisperMessage but preexisting identity key changed.");
+ }
+ this.identityKey = identityKey;
+ plaintext = cipher.decrypt(preKeySignalMessage);
+ } else {
+ SignalMessage signalMessage = new SignalMessage(encryptedKey.key);
+ try {
+ plaintext = cipher.decrypt(signalMessage);
+ } catch (InvalidMessageException | NoSessionException e) {
+ if (iterator.hasNext()) {
+ Log.w(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring crypto exception because possible keys left to try", e);
+ continue;
+ }
+ throw new BrokenSessionException(this.remoteAddress, e);
+ }
+ preKeyId = null; //better safe than sorry because we use that to do special after prekey handling
}
- preKeyId = optionalPreKeyId.get();
- if (this.identityKey != null && !this.identityKey.equals(identityKey)) {
- throw new CryptoFailedException("Received PreKeyWhisperMessage but preexisting identity key changed.");
+ } catch (InvalidVersionException | InvalidKeyException | LegacyMessageException | InvalidMessageException | DuplicateMessageException | InvalidKeyIdException | UntrustedIdentityException e) {
+ if (iterator.hasNext()) {
+ Log.w(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring crypto exception because possible keys left to try", e);
+ continue;
}
- this.identityKey = identityKey;
- plaintext = cipher.decrypt(preKeySignalMessage);
- } else {
- SignalMessage signalMessage = new SignalMessage(encryptedKey.key);
- try {
- plaintext = cipher.decrypt(signalMessage);
- } catch (InvalidMessageException | NoSessionException e) {
- throw new BrokenSessionException(this.remoteAddress, e);
- }
- preKeyId = null; //better safe than sorry because we use that to do special after prekey handling
+ throw new CryptoFailedException("Error decrypting SignalMessage", e);
+ }
+ if (iterator.hasNext()) {
+ break;
}
- } catch (InvalidVersionException | InvalidKeyException | LegacyMessageException | InvalidMessageException | DuplicateMessageException | InvalidKeyIdException | UntrustedIdentityException e) {
- throw new CryptoFailedException("Error decrypting SignalMessage", e);
}
if (!status.isActive()) {
setTrust(status.toActive());
@@ -125,7 +151,7 @@ public class XmppAxolotlSession implements Comparable<XmppAxolotlSession> {
if (ignoreSessionTrust || status.isTrustedAndActive()) {
try {
CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
- return new AxolotlKey(ciphertextMessage.serialize(), ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE);
+ return new AxolotlKey(getRemoteAddress().getDeviceId(), ciphertextMessage.serialize(), ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE);
} catch (UntrustedIdentityException e) {
return null;
}
@@ -148,8 +174,10 @@ public class XmppAxolotlSession implements Comparable<XmppAxolotlSession> {
public final byte[] key;
public final boolean prekey;
+ public final int deviceId;
- public AxolotlKey(byte[] key, boolean prekey) {
+ public AxolotlKey(int deviceId, byte[] key, boolean prekey) {
+ this.deviceId = deviceId;
this.key = key;
this.prekey = prekey;
}