Search in sources :

Example 6 with CannotEstablishOmemoSessionException

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

the class OmemoService method decryptStanza.

/**
 * Decrypt the OmemoElement inside the given Stanza and return it.
 * Return null if something goes wrong.
 *
 * @param stanza stanza
 * @param managerGuard authenticated OmemoManager
 * @return decrypted OmemoMessage or null
 *
 * @throws IOException if an I/O error occurred.
 */
OmemoMessage.Received decryptStanza(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 null;
        }
        OmemoMessage.Received decrypted = null;
        BareJid sender;
        try {
            MultiUserChat muc = getMuc(manager.getConnection(), stanza.getFrom());
            if (muc != null) {
                Occupant occupant = muc.getOccupant(stanza.getFrom().asEntityFullJidIfPossible());
                Jid occupantJid = occupant.getJid();
                if (occupantJid == null) {
                    LOGGER.log(Level.WARNING, "MUC message received, but there is no way to retrieve the senders Jid. " + stanza.getFrom());
                    return null;
                }
                sender = occupantJid.asBareJid();
                // try is for this
                decrypted = decryptMessage(managerGuard, sender, element);
            } else {
                sender = stanza.getFrom().asBareJid();
                // and this
                decrypted = decryptMessage(managerGuard, sender, element);
            }
            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);
        } 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);
            }
        }
        return decrypted;
    }
}
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 7 with CannotEstablishOmemoSessionException

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

the class OmemoService method buildMissingSessionsWithDevices.

/**
 * Build sessions with all devices from the set, we don't have a session with yet.
 * Return the set of all devices we have a session with afterwards.
 *
 * @param connection authenticated XMPP connection
 * @param userDevice our OmemoDevice
 * @param devices set of devices we may want to build a session with if necessary
 * @return set of all devices with sessions
 *
 * @throws SmackException.NotConnectedException if the XMPP connection is not connected.
 * @throws InterruptedException if the calling thread was interrupted.
 * @throws SmackException.NoResponseException if there was no response from the remote entity.
 * @throws IOException if an I/O error occurred.
 */
private Set<OmemoDevice> buildMissingSessionsWithDevices(XMPPConnection connection, OmemoDevice userDevice, Set<OmemoDevice> devices) throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException {
    Set<OmemoDevice> devicesWithSession = new HashSet<>();
    for (OmemoDevice device : devices) {
        if (hasSession(userDevice, device)) {
            devicesWithSession.add(device);
            continue;
        }
        try {
            buildFreshSessionWithDevice(connection, userDevice, device);
            devicesWithSession.add(device);
        } catch (CannotEstablishOmemoSessionException e) {
            LOGGER.log(Level.WARNING, userDevice + " cannot establish session with " + device + " because their bundle could not be fetched.", e);
        } catch (CorruptedOmemoKeyException e) {
            LOGGER.log(Level.WARNING, userDevice + " could not establish session with " + device + "because their bundle seems to be corrupt.", e);
        }
    }
    return devicesWithSession;
}
Also used : OmemoDevice(org.jivesoftware.smackx.omemo.internal.OmemoDevice) HashSet(java.util.HashSet) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)

Example 8 with CannotEstablishOmemoSessionException

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

the class OmemoService method encrypt.

/**
 * Encrypt a message with a messageKey and an IV and create an OmemoMessage from it.
 *
 * @param managerGuard authenticated OmemoManager
 * @param contactsDevices set of recipient OmemoDevices
 * @param messageKey AES key to encrypt the message
 * @param iv iv to be used with the messageKey
 * @return OmemoMessage object which contains the OmemoElement and some information.
 *
 * @throws SmackException.NotConnectedException if the XMPP connection is not connected.
 * @throws InterruptedException if the calling thread was interrupted.
 * @throws SmackException.NoResponseException if there was no response from the remote entity.
 * @throws UndecidedOmemoIdentityException if the list of recipient devices contains undecided devices
 * @throws CryptoFailedException if we are lacking some crypto primitives
 * @throws IOException if an I/O error occurred.
 */
private OmemoMessage.Sent encrypt(OmemoManager.LoggedInOmemoManager managerGuard, Set<OmemoDevice> contactsDevices, byte[] messageKey, byte[] iv, String message) throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, UndecidedOmemoIdentityException, CryptoFailedException, IOException {
    OmemoManager manager = managerGuard.get();
    OmemoDevice userDevice = manager.getOwnDevice();
    // Do not encrypt for our own device.
    removeOurDevice(userDevice, contactsDevices);
    buildMissingSessionsWithDevices(manager.getConnection(), userDevice, contactsDevices);
    Set<OmemoDevice> undecidedDevices = getUndecidedDevices(userDevice, manager.getTrustCallback(), contactsDevices);
    if (!undecidedDevices.isEmpty()) {
        throw new UndecidedOmemoIdentityException(undecidedDevices);
    }
    // Keep track of skipped devices
    HashMap<OmemoDevice, Throwable> skippedRecipients = new HashMap<>();
    OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> builder;
    try {
        builder = new OmemoMessageBuilder<>(userDevice, manager.getTrustCallback(), getOmemoRatchet(managerGuard.get()), messageKey, iv, message);
    } catch (BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchAlgorithmException e) {
        throw new CryptoFailedException(e);
    }
    for (OmemoDevice contactsDevice : contactsDevices) {
        // Build missing sessions
        if (!hasSession(userDevice, contactsDevice)) {
            try {
                buildFreshSessionWithDevice(manager.getConnection(), userDevice, contactsDevice);
            } catch (CorruptedOmemoKeyException | CannotEstablishOmemoSessionException e) {
                LOGGER.log(Level.WARNING, "Could not build session with " + contactsDevice + ".", e);
                skippedRecipients.put(contactsDevice, e);
                continue;
            }
        }
        int messageCounter = omemoStore.loadOmemoMessageCounter(userDevice, contactsDevice);
        // Ignore read-only devices
        if (OmemoConfiguration.getIgnoreReadOnlyDevices()) {
            boolean readOnly = messageCounter >= OmemoConfiguration.getMaxReadOnlyMessageCount();
            if (readOnly) {
                LOGGER.log(Level.FINE, "Device " + contactsDevice + " seems to be read-only (We sent " + messageCounter + " messages without getting a reply back (max allowed is " + OmemoConfiguration.getMaxReadOnlyMessageCount() + "). Ignoring the device.");
                skippedRecipients.put(contactsDevice, new ReadOnlyDeviceException(contactsDevice));
                // Skip this device and handle next device
                continue;
            }
        }
        // Add recipients
        try {
            builder.addRecipient(contactsDevice);
        } catch (NoIdentityKeyException | CorruptedOmemoKeyException e) {
            LOGGER.log(Level.WARNING, "Encryption failed for device " + contactsDevice + ".", e);
            skippedRecipients.put(contactsDevice, e);
        } catch (UndecidedOmemoIdentityException e) {
            throw new AssertionError("Recipients device seems to be undecided, even though we should have thrown" + " an exception earlier in that case. " + e);
        } catch (UntrustedOmemoIdentityException e) {
            LOGGER.log(Level.WARNING, "Device " + contactsDevice + " is untrusted. Message is not encrypted for it.");
            skippedRecipients.put(contactsDevice, e);
        }
        // Increment the message counter of the device
        omemoStore.storeOmemoMessageCounter(userDevice, contactsDevice, messageCounter + 1);
    }
    OmemoElement element = builder.finish();
    return new OmemoMessage.Sent(element, messageKey, iv, contactsDevices, skippedRecipients);
}
Also used : HashMap(java.util.HashMap) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) BadPaddingException(javax.crypto.BadPaddingException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) NoIdentityKeyException(org.jivesoftware.smackx.omemo.exceptions.NoIdentityKeyException) ReadOnlyDeviceException(org.jivesoftware.smackx.omemo.exceptions.ReadOnlyDeviceException) CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) UndecidedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) OmemoDevice(org.jivesoftware.smackx.omemo.internal.OmemoDevice) NoSuchPaddingException(javax.crypto.NoSuchPaddingException) InvalidKeyException(java.security.InvalidKeyException) OmemoFingerprint(org.jivesoftware.smackx.omemo.trust.OmemoFingerprint) UntrustedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UntrustedOmemoIdentityException) OmemoElement(org.jivesoftware.smackx.omemo.element.OmemoElement)

Example 9 with CannotEstablishOmemoSessionException

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

the class OmemoClient method handleInput.

public void handleInput(String input) throws NotConnectedException, NotLoggedInException, InterruptedException, IOException {
    String[] com = input.split(" ", 3);
    switch(com[0]) {
        case "/omemo":
            if (com.length < 3) {
                print("Usage: /omemo <contact-jid> <message>");
                return;
            }
            BareJid recipient = JidCreate.bareFrom(com[1]);
            String body = com[2];
            MessageBuilder messageBuilder = connection.getStanzaFactory().buildMessageStanza();
            try {
                Message omemoMessage = omemoManager.encrypt(recipient, body).buildMessage(messageBuilder, recipient);
                connection.sendStanza(omemoMessage);
            } catch (UndecidedOmemoIdentityException e) {
                print("Undecided Identities!\n" + Arrays.toString(e.getUndecidedDevices().toArray()));
            } catch (CryptoFailedException | SmackException.NoResponseException e) {
                LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
            }
            break;
        case "/trust":
            print("Trust");
            if (com.length != 2) {
                print("Usage: /trust <contact-jid>");
            }
            BareJid contact = JidCreate.bareFrom(com[1]);
            HashMap<OmemoDevice, OmemoFingerprint> devices;
            try {
                devices = omemoManager.getActiveFingerprints(contact);
            } catch (CorruptedOmemoKeyException | CannotEstablishOmemoSessionException | SmackException.NoResponseException e) {
                LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
                return;
            }
            for (OmemoDevice d : devices.keySet()) {
                print("Trust (1) or distrust (2)?\n" + devices.get(d).blocksOf8Chars());
                if (Integer.parseInt(scanner.nextLine()) == 1) {
                    omemoManager.trustOmemoIdentity(d, devices.get(d));
                } else {
                    omemoManager.distrustOmemoIdentity(d, devices.get(d));
                }
            }
            print("Done.");
            break;
        case "/purge":
            try {
                omemoManager.purgeDeviceList();
                print("Purged.");
            } catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | PubSubException.NotALeafNodeException e) {
                LOGGER.log(Level.SEVERE, "Unexpected Exception", e);
            }
    }
}
Also used : CryptoFailedException(org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException) UndecidedOmemoIdentityException(org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException) OmemoMessage(org.jivesoftware.smackx.omemo.OmemoMessage) Message(org.jivesoftware.smack.packet.Message) OmemoDevice(org.jivesoftware.smackx.omemo.internal.OmemoDevice) EntityBareJid(org.jxmpp.jid.EntityBareJid) BareJid(org.jxmpp.jid.BareJid) CorruptedOmemoKeyException(org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) MessageBuilder(org.jivesoftware.smack.packet.MessageBuilder) OmemoFingerprint(org.jivesoftware.smackx.omemo.trust.OmemoFingerprint)

Aggregations

CannotEstablishOmemoSessionException (org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException)9 OmemoDevice (org.jivesoftware.smackx.omemo.internal.OmemoDevice)8 CorruptedOmemoKeyException (org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)6 CryptoFailedException (org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException)5 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)4 OmemoBundleElement (org.jivesoftware.smackx.omemo.element.OmemoBundleElement)4 OmemoElement (org.jivesoftware.smackx.omemo.element.OmemoElement)4 NotALeafNodeException (org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException)4 BareJid (org.jxmpp.jid.BareJid)4 EntityBareJid (org.jxmpp.jid.EntityBareJid)4 NoRawSessionException (org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException)3 OmemoFingerprint (org.jivesoftware.smackx.omemo.trust.OmemoFingerprint)3 MessageOrOmemoMessage (org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage)3 MultiUserChat (org.jivesoftware.smackx.muc.MultiUserChat)2 Occupant (org.jivesoftware.smackx.muc.Occupant)2 UndecidedOmemoIdentityException (org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException)2 Jid (org.jxmpp.jid.Jid)2 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)1 InvalidKeyException (java.security.InvalidKeyException)1 ArrayList (java.util.ArrayList)1