diff options
author | Christian Schneppe <christian@pix-art.de> | 2019-01-07 20:58:37 +0100 |
---|---|---|
committer | Christian Schneppe <christian@pix-art.de> | 2019-01-07 20:58:37 +0100 |
commit | 91d8c5e9cd1ddbaeda394fb5ad570f3e30d0a0e3 (patch) | |
tree | fab895c08446779dd50b3b65b755b0dafbbf041b /src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java | |
parent | fb91826bd816ee363d509788bf9bd1276cef871e (diff) |
handle decrypting/encrypting of omemo messages with duplicate device ids
Diffstat (limited to '')
-rw-r--r-- | src/main/java/de/pixart/messenger/crypto/axolotl/XmppAxolotlSession.java | 80 |
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; } |