diff options
Diffstat (limited to 'src/main/java')
5 files changed, 56 insertions, 38 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 99533afb..6bde0fe7 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -1122,7 +1122,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { session.resetPreKeyId(); } } catch (CryptoFailedException e) { - Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message: " + e.getMessage()); + Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message from "+message.getFrom()+": " + e.getMessage()); } if (session.isFresh() && plaintextMessage != null) { @@ -1136,7 +1136,12 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { XmppAxolotlMessage.XmppAxolotlKeyTransportMessage keyTransportMessage; XmppAxolotlSession session = getReceivingSession(message); - keyTransportMessage = message.getParameters(session, getOwnDeviceId()); + try { + keyTransportMessage = message.getParameters(session, getOwnDeviceId()); + } catch (CryptoFailedException e) { + Log.d(Config.LOGTAG,"could not decrypt keyTransport message "+e.getMessage()); + keyTransportMessage = null; + } if (session.isFresh() && keyTransportMessage != null) { putFreshSession(session); diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java index 5796ef30..e549598c 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/CryptoFailedException.java @@ -1,6 +1,11 @@ package eu.siacs.conversations.crypto.axolotl; public class CryptoFailedException extends Exception { + + public CryptoFailedException(String msg) { + super(msg); + } + public CryptoFailedException(Exception e){ super(e); } diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java index e5e7b203..cac298e0 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java @@ -250,16 +250,16 @@ public class XmppAxolotlMessage { return encryptionElement; } - private byte[] unpackKey(XmppAxolotlSession session, Integer sourceDeviceId) { + private byte[] unpackKey(XmppAxolotlSession session, Integer sourceDeviceId) throws CryptoFailedException { XmppAxolotlSession.AxolotlKey encryptedKey = keys.get(sourceDeviceId); - return (encryptedKey != null) ? session.processReceiving(encryptedKey) : null; + if (encryptedKey == null) { + throw new CryptoFailedException("Message was not encrypted for this device"); + } + return session.processReceiving(encryptedKey); } - public XmppAxolotlKeyTransportMessage getParameters(XmppAxolotlSession session, Integer sourceDeviceId) { - byte[] key = unpackKey(session, sourceDeviceId); - return (key != null) - ? new XmppAxolotlKeyTransportMessage(session.getFingerprint(), key, getIV()) - : null; + public XmppAxolotlKeyTransportMessage getParameters(XmppAxolotlSession session, Integer sourceDeviceId) throws CryptoFailedException { + return new XmppAxolotlKeyTransportMessage(session.getFingerprint(), unpackKey(session, sourceDeviceId), getIV()); } public XmppAxolotlPlaintextMessage decrypt(XmppAxolotlSession session, Integer sourceDeviceId) throws CryptoFailedException { diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java index 938c19a4..359cb7fd 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java @@ -4,6 +4,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; +import org.bouncycastle.math.ec.PreCompInfo; import org.whispersystems.libaxolotl.AxolotlAddress; import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.IdentityKey; @@ -18,9 +19,11 @@ 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.util.guava.Optional; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.utils.CryptoHelper; public class XmppAxolotlSession implements Comparable<XmppAxolotlSession> { private final SessionCipher cipher; @@ -82,44 +85,43 @@ public class XmppAxolotlSession implements Comparable<XmppAxolotlSession> { } @Nullable - public byte[] processReceiving(AxolotlKey encryptedKey) { - byte[] plaintext = null; + public byte[] processReceiving(AxolotlKey encryptedKey) throws CryptoFailedException { + byte[] plaintext; FingerprintStatus status = getTrust(); if (!status.isCompromised()) { try { + CiphertextMessage ciphertextMessage; try { - PreKeyWhisperMessage message = new PreKeyWhisperMessage(encryptedKey.key); - if (!message.getPreKeyId().isPresent()) { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage did not contain a PreKeyId"); - return null; + ciphertextMessage = new PreKeyWhisperMessage(encryptedKey.key); + Optional<Integer> optionalPreKeyId = ((PreKeyWhisperMessage) ciphertextMessage).getPreKeyId(); + IdentityKey identityKey = ((PreKeyWhisperMessage) ciphertextMessage).getIdentityKey(); + if (!optionalPreKeyId.isPresent()) { + throw new CryptoFailedException("PreKeyWhisperMessage did not contain a PreKeyId"); } - Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId()); - IdentityKey msgIdentityKey = message.getIdentityKey(); - if (this.identityKey != null && !this.identityKey.equals(msgIdentityKey)) { - Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Had session with fingerprint " + this.getFingerprint() + ", received message with fingerprint " + msgIdentityKey.getFingerprint()); - } else { - this.identityKey = msgIdentityKey; - plaintext = cipher.decrypt(message); - preKeyId = message.getPreKeyId().get(); + preKeyId = optionalPreKeyId.get(); + if (this.identityKey != null && !this.identityKey.equals(identityKey)) { + throw new CryptoFailedException("Received PreKeyWhisperMessage but preexisting identity key changed."); } - } catch (InvalidMessageException | InvalidVersionException e) { - Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "WhisperMessage received"); - WhisperMessage message = new WhisperMessage(encryptedKey.key); - plaintext = cipher.decrypt(message); - } catch (InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e) { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error decrypting axolotl header, " + e.getClass().getName() + ": " + e.getMessage()); + this.identityKey = identityKey; + } catch (InvalidVersionException | InvalidMessageException e) { + ciphertextMessage = new WhisperMessage(encryptedKey.key); } - } catch (LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e) { - Log.w(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Error decrypting axolotl header, " + e.getClass().getName() + ": " + e.getMessage()); - } - - if (plaintext != null) { - if (!status.isActive()) { - setTrust(status.toActive()); + if (ciphertextMessage instanceof PreKeyWhisperMessage) { + plaintext = cipher.decrypt((PreKeyWhisperMessage) ciphertextMessage); + } else { + plaintext = cipher.decrypt((WhisperMessage) ciphertextMessage); } + } catch (InvalidKeyException | LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException | InvalidKeyIdException | UntrustedIdentityException e) { + if (!(e instanceof DuplicateMessageException)) { + e.printStackTrace(); + } + throw new CryptoFailedException("Error decrypting WhisperMessage " + e.getClass().getSimpleName() + ": " + e.getMessage()); + } + if (!status.isActive()) { + setTrust(status.toActive()); } } else { - Log.d(Config.LOGTAG,account.getJid().toBareJid()+" not encrypting omemo message from fingerprint "+getFingerprint()+" because it was marked as compromised"); + throw new CryptoFailedException("not encrypting omemo message from fingerprint "+getFingerprint()+" because it was marked as compromised"); } return plaintext; } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index ce56e30c..6188b629 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -88,6 +88,12 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie } } }; + private static final Linkify.MatchFilter WEBURL_MATCH_FILTER = new Linkify.MatchFilter() { + @Override + public boolean acceptMatch(CharSequence charSequence, int start, int end) { + return start < 1 || charSequence.charAt(start-1) != '@'; + } + }; private ConversationActivity activity; @@ -442,8 +448,8 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie privateMarkerIndex + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } - Linkify.addLinks(body, Patterns.AUTOLINK_WEB_URL, "http", null, WEBURL_TRANSFORM_FILTER); Linkify.addLinks(body, XMPP_PATTERN, "xmpp"); + Linkify.addLinks(body, Patterns.AUTOLINK_WEB_URL, "http", WEBURL_MATCH_FILTER, WEBURL_TRANSFORM_FILTER); Linkify.addLinks(body, GeoHelper.GEO_URI, "geo"); viewHolder.messageBody.setAutoLinkMask(0); viewHolder.messageBody.setText(body); |