Search in sources :

Example 1 with OmemoBundleElement

use of org.jivesoftware.smackx.omemo.element.OmemoBundleElement in project Smack by igniterealtime.

the class MessageEncryptionIntegrationTest method messageTest.

/**
 * This test checks whether the following actions are performed.
 *
 * Alice publishes bundle A1
 * Bob publishes bundle B1
 *
 * Alice sends message to Bob (preKeyMessage)
 * Bob publishes bundle B2
 * Alice still has A1
 *
 * Bob responds to Alice (normal message)
 * Alice still has A1
 * Bob still has B2
 * @throws Exception if an exception occurs.
 */
@SuppressWarnings("SynchronizeOnNonFinalField")
@SmackIntegrationTest
public void messageTest() throws Exception {
    OmemoBundleElement a1 = alice.getOmemoService().getOmemoStoreBackend().packOmemoBundle(alice.getOwnDevice());
    OmemoBundleElement b1 = bob.getOmemoService().getOmemoStoreBackend().packOmemoBundle(bob.getOwnDevice());
    // Alice sends message(s) to bob
    // PreKeyMessage A -> B
    final String body1 = "One is greater than zero (for small values of zero).";
    AbstractOmemoMessageListener.PreKeyMessageListener listener1 = new AbstractOmemoMessageListener.PreKeyMessageListener(body1);
    bob.addOmemoMessageListener(listener1);
    OmemoMessage.Sent e1 = alice.encrypt(bob.getOwnJid(), body1);
    XMPPConnection alicesConnection = alice.getConnection();
    MessageBuilder messageBuilder = alicesConnection.getStanzaFactory().buildMessageStanza();
    alicesConnection.sendStanza(e1.buildMessage(messageBuilder, bob.getOwnJid()));
    listener1.getSyncPoint().waitForResult(10 * 1000);
    bob.removeOmemoMessageListener(listener1);
    OmemoBundleElement a1_ = alice.getOmemoService().getOmemoStoreBackend().packOmemoBundle(alice.getOwnDevice());
    OmemoBundleElement b2;
    synchronized (bob) {
        // Circumvent race condition where bundle gets replenished after getting stored in b2
        b2 = bob.getOmemoService().getOmemoStoreBackend().packOmemoBundle(bob.getOwnDevice());
    }
    assertEquals(a1, a1_, "Alice sent bob a preKeyMessage, so her bundle MUST still be the same.");
    assertNotEquals(b1, b2, "Bob just received a preKeyMessage from alice, so his bundle must have changed.");
    // Message B -> A
    final String body3 = "The german words for 'leek' and 'wimp' are the same.";
    AbstractOmemoMessageListener.MessageListener listener3 = new AbstractOmemoMessageListener.MessageListener(body3);
    alice.addOmemoMessageListener(listener3);
    OmemoMessage.Sent e3 = bob.encrypt(alice.getOwnJid(), body3);
    XMPPConnection bobsConnection = bob.getConnection();
    messageBuilder = bobsConnection.getStanzaFactory().buildMessageStanza();
    bobsConnection.sendStanza(e3.buildMessage(messageBuilder, alice.getOwnJid()));
    listener3.getSyncPoint().waitForResult(10 * 1000);
    alice.removeOmemoMessageListener(listener3);
    OmemoBundleElement a1__ = alice.getOmemoService().getOmemoStoreBackend().packOmemoBundle(alice.getOwnDevice());
    OmemoBundleElement b2_ = bob.getOmemoService().getOmemoStoreBackend().packOmemoBundle(bob.getOwnDevice());
    assertEquals(a1_, a1__, "Since alice initiated the session with bob, at no time he sent a preKeyMessage, " + "so her bundle MUST still be the same.");
    assertEquals(b2, b2_, "Bob changed his bundle earlier, but at this point his bundle must be equal to " + "after the first change.");
}
Also used : MessageBuilder(org.jivesoftware.smack.packet.MessageBuilder) OmemoBundleElement(org.jivesoftware.smackx.omemo.element.OmemoBundleElement) XMPPConnection(org.jivesoftware.smack.XMPPConnection) SmackIntegrationTest(org.igniterealtime.smack.inttest.annotations.SmackIntegrationTest)

Example 2 with OmemoBundleElement

use of org.jivesoftware.smackx.omemo.element.OmemoBundleElement 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 3 with OmemoBundleElement

use of org.jivesoftware.smackx.omemo.element.OmemoBundleElement 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 OmemoBundleElement

use of org.jivesoftware.smackx.omemo.element.OmemoBundleElement in project Smack by igniterealtime.

the class OmemoService method buildFreshSessionWithDevice.

/**
 * Fetch the bundle of a contact and build a fresh OMEMO session with the contacts device.
 * Note that this builds a fresh session, regardless if we have had a session before or not.
 *
 * @param connection authenticated XMPP connection
 * @param userDevice our OmemoDevice
 * @param contactsDevice OmemoDevice of a contact.
 *
 * @throws CannotEstablishOmemoSessionException if we cannot establish a session (because of missing bundle etc.)
 * @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 CorruptedOmemoKeyException if our IdentityKeyPair is corrupted.
 */
void buildFreshSessionWithDevice(XMPPConnection connection, OmemoDevice userDevice, OmemoDevice contactsDevice) throws CannotEstablishOmemoSessionException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, CorruptedOmemoKeyException {
    if (contactsDevice.equals(userDevice)) {
        // Do not build a session with yourself.
        return;
    }
    OmemoBundleElement bundleElement;
    try {
        bundleElement = fetchBundle(connection, contactsDevice);
    } catch (XMPPException.XMPPErrorException | PubSubException.NotALeafNodeException | PubSubException.NotAPubSubNodeException e) {
        throw new CannotEstablishOmemoSessionException(contactsDevice, e);
    }
    // Select random Bundle
    HashMap<Integer, T_Bundle> bundlesList = getOmemoStoreBackend().keyUtil().BUNDLE.bundles(bundleElement, contactsDevice);
    int randomIndex = new Random().nextInt(bundlesList.size());
    T_Bundle randomPreKeyBundle = new ArrayList<>(bundlesList.values()).get(randomIndex);
    // build the session
    OmemoManager omemoManager = OmemoManager.getInstanceFor(connection, userDevice.getDeviceId());
    processBundle(omemoManager, randomPreKeyBundle, contactsDevice);
}
Also used : NotALeafNodeException(org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException) OmemoBundleElement(org.jivesoftware.smackx.omemo.element.OmemoBundleElement) OmemoFingerprint(org.jivesoftware.smackx.omemo.trust.OmemoFingerprint) CannotEstablishOmemoSessionException(org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException) Random(java.util.Random)

Example 5 with OmemoBundleElement

use of org.jivesoftware.smackx.omemo.element.OmemoBundleElement in project Smack by igniterealtime.

the class OmemoManager method rotateSignedPreKey.

/**
 * Rotate the signedPreKey published in our OmemoBundle and republish it. This should be done every now and
 * then (7-14 days). The old signedPreKey should be kept for some more time (a month or so) to enable decryption
 * of messages that have been sent since the key was changed.
 *
 * @throws CorruptedOmemoKeyException When the IdentityKeyPair is damaged.
 * @throws InterruptedException XMPP error
 * @throws XMPPException.XMPPErrorException XMPP error
 * @throws SmackException.NotConnectedException XMPP error
 * @throws SmackException.NoResponseException XMPP error
 * @throws SmackException.NotLoggedInException if the XMPP connection is not authenticated.
 * @throws IOException if an I/O error occurred.
 * @throws PubSubException.NotALeafNodeException if a PubSub leaf node operation was attempted on a non-leaf node.
 */
public synchronized void rotateSignedPreKey() throws CorruptedOmemoKeyException, SmackException.NotLoggedInException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException, PubSubException.NotALeafNodeException {
    if (!connection().isAuthenticated()) {
        throw new SmackException.NotLoggedInException();
    }
    // generate key
    getOmemoService().getOmemoStoreBackend().changeSignedPreKey(getOwnDevice());
    // publish
    OmemoBundleElement bundle = getOmemoService().getOmemoStoreBackend().packOmemoBundle(getOwnDevice());
    OmemoService.publishBundle(connection(), getOwnDevice(), bundle);
}
Also used : OmemoBundleElement(org.jivesoftware.smackx.omemo.element.OmemoBundleElement)

Aggregations

OmemoBundleElement (org.jivesoftware.smackx.omemo.element.OmemoBundleElement)7 CannotEstablishOmemoSessionException (org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException)4 OmemoDevice (org.jivesoftware.smackx.omemo.internal.OmemoDevice)4 NotALeafNodeException (org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException)4 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)3 OmemoElement (org.jivesoftware.smackx.omemo.element.OmemoElement)3 CorruptedOmemoKeyException (org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException)3 CryptoFailedException (org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException)3 NoRawSessionException (org.jivesoftware.smackx.omemo.exceptions.NoRawSessionException)3 MessageOrOmemoMessage (org.jivesoftware.smackx.omemo.util.MessageOrOmemoMessage)3 BareJid (org.jxmpp.jid.BareJid)3 EntityBareJid (org.jxmpp.jid.EntityBareJid)3 MultiUserChat (org.jivesoftware.smackx.muc.MultiUserChat)2 Occupant (org.jivesoftware.smackx.muc.Occupant)2 Jid (org.jxmpp.jid.Jid)2 Random (java.util.Random)1 SmackIntegrationTest (org.igniterealtime.smack.inttest.annotations.SmackIntegrationTest)1 XMPPConnection (org.jivesoftware.smack.XMPPConnection)1 MessageBuilder (org.jivesoftware.smack.packet.MessageBuilder)1 OmemoFingerprint (org.jivesoftware.smackx.omemo.trust.OmemoFingerprint)1