Search in sources :

Example 1 with CryptoFailedException

use of org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException in project Smack by igniterealtime.

the class OmemoService method onOmemoMessageStanzaReceived.

@Override
public void onOmemoMessageStanzaReceived(Stanza stanza, OmemoManager.LoggedInOmemoManager managerGuard) throws IOException {
    OmemoManager manager = managerGuard.get();
    // Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
    synchronized (manager) {
        OmemoDevice userDevice = manager.getOwnDevice();
        OmemoElement element = (OmemoElement) stanza.getExtensionElement(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
        if (element == null) {
            return;
        }
        OmemoMessage.Received decrypted;
        BareJid sender;
        try {
            MultiUserChat muc = getMuc(manager.getConnection(), stanza.getFrom());
            if (muc != null) {
                Occupant occupant = muc.getOccupant(stanza.getFrom().asEntityFullJidIfPossible());
                if (occupant == null) {
                    LOGGER.log(Level.WARNING, "Cannot decrypt OMEMO MUC message; MUC Occupant is null.");
                    return;
                }
                Jid occupantJid = occupant.getJid();
                if (occupantJid == null) {
                    LOGGER.log(Level.WARNING, "Cannot decrypt OMEMO MUC message; Senders Jid is null. " + stanza.getFrom());
                    return;
                }
                sender = occupantJid.asBareJid();
                // try is for this
                decrypted = decryptMessage(managerGuard, sender, element);
                manager.notifyOmemoMucMessageReceived(muc, stanza, decrypted);
            } else {
                sender = stanza.getFrom().asBareJid();
                // and this
                decrypted = decryptMessage(managerGuard, sender, element);
                manager.notifyOmemoMessageReceived(stanza, decrypted);
            }
            if (decrypted.isPreKeyMessage() && OmemoConfiguration.getCompleteSessionWithEmptyMessage()) {
                LOGGER.log(Level.FINE, "Received a preKeyMessage from " + decrypted.getSenderDevice() + ".\n" + "Complete the session by sending an empty response message.");
                try {
                    sendRatchetUpdate(managerGuard, decrypted.getSenderDevice());
                } catch (CannotEstablishOmemoSessionException e) {
                    throw new AssertionError("Since we successfully received a message, we MUST be able to " + "establish a session. " + e);
                } catch (NoSuchAlgorithmException | InterruptedException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
                    LOGGER.log(Level.WARNING, "Cannot send a ratchet update message.", e);
                }
            }
        } catch (NoRawSessionException e) {
            OmemoDevice device = e.getDeviceWithoutSession();
            LOGGER.log(Level.WARNING, "No raw session found for contact " + device + ". ", e);
            if (OmemoConfiguration.getRepairBrokenSessionsWithPreKeyMessages()) {
                repairBrokenSessionWithPreKeyMessage(managerGuard, device);
            }
        } catch (CorruptedOmemoKeyException | CryptoFailedException e) {
            LOGGER.log(Level.WARNING, "Could not decrypt incoming message: ", e);
        }
        // Upload fresh bundle.
        if (getOmemoStoreBackend().loadOmemoPreKeys(userDevice).size() < OmemoConstants.PRE_KEY_COUNT_PER_BUNDLE) {
            LOGGER.log(Level.FINE, "We used up a preKey. Upload a fresh bundle.");
            try {
                getOmemoStoreBackend().replenishKeys(userDevice);
                OmemoBundleElement bundleElement = getOmemoStoreBackend().packOmemoBundle(userDevice);
                publishBundle(manager.getConnection(), userDevice, bundleElement);
            } catch (CorruptedOmemoKeyException | InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | NotALeafNodeException e) {
                LOGGER.log(Level.WARNING, "Could not republish replenished bundle.", e);
            }
        }
    }
}
Also used : CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) MultiUserChat(org.jivesoftware.smackx.muc.MultiUserChat) OmemoDevice(org.jivesoftware.smackx.omemo.internal.OmemoDevice) EntityBareJid(org.jxmpp.jid.EntityBareJid) Jid(org.jxmpp.jid.Jid) BareJid(org.jxmpp.jid.BareJid) NotALeafNodeException(org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException) EntityBareJid(org.jxmpp.jid.EntityBareJid) BareJid(org.jxmpp.jid.BareJid) Occupant(org.jivesoftware.smackx.muc.Occupant) NoRawSessionException(org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException) MessageOrOmemoMessage(org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) OmemoBundleElement(org.jivesoftware.smackx.omemo.element.OmemoBundleElement) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException) OmemoElement(org.jivesoftware.smackx.omemo.element.OmemoElement)

Example 2 with CryptoFailedException

use of org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException in project Smack by igniterealtime.

the class OmemoService method decryptMamQueryResult.

/**
 * Decrypt a possible OMEMO encrypted messages in a {@link MamManager.MamQuery}.
 * The returned list contains wrappers that either hold an {@link OmemoMessage} in case the message was decrypted
 * properly, otherwise it contains the message itself.
 *
 * @param managerGuard authenticated OmemoManager.
 * @param mamQuery Mam archive query
 * @return list of {@link MessageOrOmemoMessage MessageOrOmemoMessages}.
 *
 * @throws IOException if an I/O error occurred.
 */
List<MessageOrOmemoMessage> decryptMamQueryResult(OmemoManager.LoggedInOmemoManager managerGuard, MamManager.MamQuery mamQuery) throws IOException {
    List<MessageOrOmemoMessage> result = new ArrayList<>();
    for (Message message : mamQuery.getMessages()) {
        if (OmemoManager.stanzaContainsOmemoElement(message)) {
            OmemoElement element = (OmemoElement) message.getExtensionElement(OmemoElement.NAME_ENCRYPTED, OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL);
            // Decrypt OMEMO messages
            try {
                OmemoMessage.Received omemoMessage = decryptMessage(managerGuard, message.getFrom().asBareJid(), element);
                result.add(new MessageOrOmemoMessage(omemoMessage));
            } catch (NoRawSessionException | CorruptedOmemoKeyException | CryptoFailedException e) {
                LOGGER.log(Level.WARNING, "decryptMamQueryResult failed to decrypt message from " + message.getFrom() + " due to corrupted session/key: " + e.getMessage());
                result.add(new MessageOrOmemoMessage(message));
            }
        } else {
            // Wrap cleartext messages
            result.add(new MessageOrOmemoMessage(message));
        }
    }
    return result;
}
Also used : CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) MessageOrOmemoMessage(org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage) MessageOrOmemoMessage(org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage) Message(org.jivesoftware.smack.packet.Message) NoRawSessionException(org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException) ArrayList(java.util.ArrayList) MessageOrOmemoMessage(org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage) OmemoElement(org.jivesoftware.smackx.omemo.element.OmemoElement) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)

Example 3 with CryptoFailedException

use of org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException in project Smack by igniterealtime.

the class OmemoService method onOmemoCarbonCopyReceived.

@Override
public void onOmemoCarbonCopyReceived(CarbonExtension.Direction direction, Message carbonCopy, Message wrappingMessage, OmemoManager.LoggedInOmemoManager managerGuard) throws IOException {
    OmemoManager manager = managerGuard.get();
    // Avoid the ratchet being manipulated and the bundle being published multiple times simultaneously
    synchronized (manager) {
        OmemoDevice userDevice = manager.getOwnDevice();
        OmemoElement element = (OmemoElement) carbonCopy.getExtensionElement(OmemoElement.NAME_ENCRYPTED, OmemoElement_VAxolotl.NAMESPACE);
        if (element == null) {
            return;
        }
        OmemoMessage.Received decrypted;
        BareJid sender = carbonCopy.getFrom().asBareJid();
        try {
            decrypted = decryptMessage(managerGuard, sender, element);
            manager.notifyOmemoCarbonCopyReceived(direction, carbonCopy, wrappingMessage, decrypted);
            if (decrypted.isPreKeyMessage() && OmemoConfiguration.getCompleteSessionWithEmptyMessage()) {
                LOGGER.log(Level.FINE, "Received a preKeyMessage in a carbon copy from " + decrypted.getSenderDevice() + ".\n" + "Complete the session by sending an empty response message.");
                try {
                    sendRatchetUpdate(managerGuard, decrypted.getSenderDevice());
                } catch (CannotEstablishOmemoSessionException e) {
                    throw new AssertionError("Since we successfully received a message, we MUST be able to " + "establish a session. " + e);
                } catch (NoSuchAlgorithmException | InterruptedException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
                    LOGGER.log(Level.WARNING, "Cannot send a ratchet update message.", e);
                }
            }
        } catch (NoRawSessionException e) {
            OmemoDevice device = e.getDeviceWithoutSession();
            LOGGER.log(Level.WARNING, "No raw session found for contact " + device + ". ", e);
            if (OmemoConfiguration.getRepairBrokenSessionsWithPreKeyMessages()) {
                repairBrokenSessionWithPreKeyMessage(managerGuard, device);
            }
        } catch (CorruptedOmemoKeyException | CryptoFailedException e) {
            LOGGER.log(Level.WARNING, "Could not decrypt incoming carbon copy: ", e);
        }
        // Upload fresh bundle.
        if (getOmemoStoreBackend().loadOmemoPreKeys(userDevice).size() < OmemoConstants.PRE_KEY_COUNT_PER_BUNDLE) {
            LOGGER.log(Level.FINE, "We used up a preKey. Upload a fresh bundle.");
            try {
                getOmemoStoreBackend().replenishKeys(userDevice);
                OmemoBundleElement bundleElement = getOmemoStoreBackend().packOmemoBundle(userDevice);
                publishBundle(manager.getConnection(), userDevice, bundleElement);
            } catch (CorruptedOmemoKeyException | InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException | NotALeafNodeException e) {
                LOGGER.log(Level.WARNING, "Could not republish replenished bundle.", e);
            }
        }
    }
}
Also used : CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) OmemoDevice(org.jivesoftware.smackx.omemo.internal.OmemoDevice) NotALeafNodeException(org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException) EntityBareJid(org.jxmpp.jid.EntityBareJid) BareJid(org.jxmpp.jid.BareJid) NoRawSessionException(org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException) MessageOrOmemoMessage(org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) OmemoBundleElement(org.jivesoftware.smackx.omemo.element.OmemoBundleElement) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException) OmemoElement(org.jivesoftware.smackx.omemo.element.OmemoElement)

Example 4 with CryptoFailedException

use of org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException in project Smack by igniterealtime.

the class OmemoRatchet method retrieveMessageKeyAndAuthTag.

/**
 * Try to decrypt the transported message key using the double ratchet session.
 *
 * @param element omemoElement
 * @return tuple of cipher generated from the unpacked message key and the auth-tag
 *
 * @throws CryptoFailedException if decryption using the double ratchet fails
 * @throws NoRawSessionException if we have no session, but the element was NOT a PreKeyMessage
 * @throws IOException if an I/O error occurred.
 */
CipherAndAuthTag retrieveMessageKeyAndAuthTag(OmemoDevice sender, OmemoElement element) throws CryptoFailedException, NoRawSessionException, IOException {
    int keyId = omemoManager.getDeviceId();
    byte[] unpackedKey = null;
    List<CryptoFailedException> decryptExceptions = new ArrayList<>();
    List<OmemoKeyElement> keys = element.getHeader().getKeys();
    boolean preKey = false;
    // Find key with our ID.
    for (OmemoKeyElement k : keys) {
        if (k.getId() == keyId) {
            try {
                unpackedKey = doubleRatchetDecrypt(sender, k.getData());
                preKey = k.isPreKey();
                break;
            } catch (CryptoFailedException e) {
                // There might be multiple keys with our id, but we can only decrypt one.
                // So we can't throw the exception, when decrypting the first duplicate which is not for us.
                decryptExceptions.add(e);
            } catch (CorruptedOmemoKeyException e) {
                decryptExceptions.add(new CryptoFailedException(e));
            } catch (UntrustedOmemoIdentityException e) {
                LOGGER.log(Level.WARNING, "Received message from " + sender + " contained unknown identityKey. Ignore message.", e);
            }
        }
    }
    if (unpackedKey == null) {
        if (!decryptExceptions.isEmpty()) {
            throw MultipleCryptoFailedException.from(decryptExceptions);
        }
        throw new CryptoFailedException("Transported key could not be decrypted, since no suitable message key " + "was provided. Provides keys: " + keys);
    }
    // Split in AES auth-tag and key
    byte[] messageKey = new byte[16];
    byte[] authTag = null;
    if (unpackedKey.length == 32) {
        authTag = new byte[16];
        // copy key part into messageKey
        System.arraycopy(unpackedKey, 0, messageKey, 0, 16);
        // copy tag part into authTag
        System.arraycopy(unpackedKey, 16, authTag, 0, 16);
    } else if (element.isKeyTransportElement() && unpackedKey.length == 16) {
        messageKey = unpackedKey;
    } else {
        throw new CryptoFailedException("MessageKey has wrong length: " + unpackedKey.length + ". Probably legacy auth tag format.");
    }
    return new CipherAndAuthTag(messageKey, element.getHeader().getIv(), authTag, preKey);
}
Also used : MultipleCryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException) CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) OmemoKeyElement(org.jivesoftware.smackx.omemo.element.OmemoKeyElement) ArrayList(java.util.ArrayList) CipherAndAuthTag(org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag) UntrustedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)

Example 5 with CryptoFailedException

use of org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException in project Smack by igniterealtime.

the class OmemoExceptionsTest method multipleCryptoFailedExceptionTest.

@Test
public void multipleCryptoFailedExceptionTest() {
    CryptoFailedException e1 = new CryptoFailedException("Fail");
    CryptoFailedException e2 = new CryptoFailedException("EpicFail");
    ArrayList<CryptoFailedException> l = new ArrayList<>();
    l.add(e1);
    l.add(e2);
    MultipleCryptoFailedException m = MultipleCryptoFailedException.from(l);
    assertEquals(2, m.getCryptoFailedExceptions().size());
    assertTrue(m.getCryptoFailedExceptions().contains(e1));
    assertTrue(m.getCryptoFailedExceptions().contains(e2));
    ArrayList<CryptoFailedException> el = new ArrayList<>();
    try {
        MultipleCryptoFailedException m2 = MultipleCryptoFailedException.from(el);
        fail("MultipleCryptoFailedException must not allow empty list, but returned: " + m2);
    } catch (IllegalArgumentException e) {
    // Expected
    }
}
Also used : MultipleCryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException) CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) ArrayList(java.util.ArrayList) MultipleCryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException) Test(org.junit.Test)

Aggregations

CryptoFailedException (org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException)11 CorruptedOmemoKeyException (org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)7 OmemoDevice (org.jivesoftware.smackx.omemo.internal.OmemoDevice)6 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)5 OmemoElement (org.jivesoftware.smackx.omemo.element.OmemoElement)5 CannotEstablishOmemoSessionException (org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException)5 NoRawSessionException (org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException)5 UntrustedOmemoIdentityException (org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException)4 MessageOrOmemoMessage (org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage)4 BareJid (org.jxmpp.jid.BareJid)4 EntityBareJid (org.jxmpp.jid.EntityBareJid)4 ArrayList (java.util.ArrayList)3 OmemoBundleElement (org.jivesoftware.smackx.omemo.element.OmemoBundleElement)3 UndecidedOmemoIdentityException (org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException)3 NotALeafNodeException (org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException)3 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)2 InvalidKeyException (java.security.InvalidKeyException)2 BadPaddingException (javax.crypto.BadPaddingException)2 IllegalBlockSizeException (javax.crypto.IllegalBlockSizeException)2 NoSuchPaddingException (javax.crypto.NoSuchPaddingException)2