powered by Jive Software

Support for carbon in omemo, it is not clear how to ensure that the sent message is decrypted on my second device

I use the smack “4.4.0-alpha2”, carbon is enabled, messages are delivered from my account 01@akk.com on all devices with an account 02@akk.com, problem with decryption on my second device with the account 01@akk.com I would like to sync sent messages with all devices that are online.

when sending a message to a second device 01@akk.com an error arrives.

2021-04-17 18:02:51.178 22824-22939/com.ef.messenger D/SMACK: RECV (0): 
    <message type="chat" from="devtest05@encryptfortress.com" to="devtest05@encryptfortress.com/EFMessenger-691">
      <sent xmlns="urn:xmpp:carbons:2">
        <forwarded xmlns="urn:xmpp:forward:0">
          <message xmlns="jabber:client" to="devtest06@encryptfortress.com" id="VVPSQ-105" type="chat" from="devtest05@encryptfortress.com/EFMessenger-610">
            <encrypted xmlns="eu.siacs.conversations.axolotl">
              <header sid="730183063">
                <key rid="1453969387">
                  MwohBc+6HjiAHmQVDEV7PRpapPqZXgQSxa0YDqqgSewB62kxED0Y0QYiMHxjxYt8gI/BDMND+iH9a3n0XPLP59+9p+n61Bif7FhWSkHhkk56DTtlo4Ke7yxydUY9vVurmeTr
                </key>
                <iv>
                  uyoozoUdg8eVVuhwBAHhWA==
                </iv>
              </header>
              <payload>
                tQ==
              </payload>
            </encrypted>
            <store xmlns="urn:xmpp:hints">
            </store>
            <encryption xmlns="urn:xmpp:eme:0" namespace="eu.siacs.conversations.axolotl" name="OMEMO">
            </encryption>
          </message>
        </forwarded>
      </sent>
    </message>
2021-04-17 18:02:51.184 22824-22967/com.ef.messenger W/OmemoService: Could not decrypt incoming carbon copy: 
    org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException: Transported key could not be decrypted, since no suitable message key was provided. Provides keys: [1453969387]
        at org.jivesoftware.smackx.omemo.OmemoRatchet.retrieveMessageKeyAndAuthTag(OmemoRatchet.java:123)
        at org.jivesoftware.smackx.omemo.OmemoService.decryptMessage(OmemoService.java:456)
        at org.jivesoftware.smackx.omemo.OmemoService.onOmemoCarbonCopyReceived(OmemoService.java:1079)
        at org.jivesoftware.smackx.omemo.OmemoManager$4$1.run(OmemoManager.java:980)
        at java.lang.Thread.run(Thread.java:923)

It looks like I don’t have a session with my second device and there is no key for it, but can sessions be built with my own devices? in general, I would like to clarify this point.

note. English is not my native language, I wrote with the help of Google translator.)

1 Like

With OMEMO encryption, sessions are being built between all devices which are participating in the conversation. That means that Alice’s phone builds a session with Bob’s phone, Bob’s Laptop, as well as Alice’s desktop client.
A device does not build a session with itself, but the implementation is preventing that, so no need to worry about this.

In your case it seems that the device that sent the message did not encrypt it for the receiving device. That can mean different things. Either the sending device is not aware of the receiving device and has not yet established a session with it, or the sending device does not trust the recipients key and has therefore decided not to encrypt for it.

On the sending device, make sure that the OmemoDevice of the recipient is trusted.
Also you can check if the sender is aware of the recipient device by calling omemoManager.getDevicesOf(bareJid). If the list does not contain the recipients device, you can try to refresh the device list by calling omemoManager.requestDeviceListUpdateFor(bareJid).

If the device still doesn’t show up, its likely that the receiving device hasn’t published its OMEMO keys and/or hasn’t added itself to the device list.

2 Likes

Thank you for answering me.

the sender can only find out about sessions with the account 02@akk.com but my devices won’t be shown there.
here are my settings.

        SignalOmemoService.acknowledgeLicense()
        SignalOmemoService.setup()

        OmemoConfiguration.setAddOmemoHintBody(false)
        OmemoConfiguration.setRenewOldSignedPreKeys(true)
        OmemoConfiguration.setDeleteStaleDevices(true)

        OmemoConfiguration.setRepairBrokenSessionsWithPrekeyMessages(true)

this is after authorization.

 override fun authenticated() {
        manager = OmemoManager.getInstanceFor(connection, deviceID).apply {
            try {
                //can only be set once
                setTrustCallback(trustCallback)
            } catch (ex: Exception) {
                logD { "trustCallback is installed" }
            }
            CarbonManager.getInstanceFor(connection).enableCarbons()

            addOmemoMessageListener(messageListener)
            addOmemoMucMessageListener(mucMessageListener)
            try {
                initialize()
                omemoInitializeSuccess?.invoke(this)
            } catch (e: Exception) {
                omemoInitializeFailed?.invoke(e)
            }
        }
    }

there are 3 devices in the test:

The app is installed from scratch on all devices, the message was sent from 01@akk.com: 1369018014 on 02@akk.com: 691929595.

error: 01@akk.com: 1369018014 cannot establish a session with its second device 01@akk.com: 681702461

2021-04-21 00:00:24.345 5706-6310/com.ef.messenger D/SMACK: SENT (0): 
    <iq id='XGM33-112' type='get'>
      <query xmlns='http://jabber.org/protocol/disco#info' node='eu.siacs.conversations.axolotl.bundles:681702461'>
      </query>
    </iq>
2021-04-21 00:00:24.740 5706-6311/com.ef.messenger D/SMACK: RECV (0): 
    <iq type="error" id="XGM33-112" to="01@akk.com/Messenger-602">
      <query xmlns="http://jabber.org/protocol/disco#info" node="eu.siacs.conversations.axolotl.bundles:681702461">
      </query>
      <error code="404" type="cancel">
        <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
      </error>
    </iq>
2021-04-21 00:00:24.741 5706-6392/messenger W/OmemoService: 01@akk.com:1369018014 cannot establish session with 01@akk.com:681702461 because their bundle could not be fetched.
    org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException
        at org.jivesoftware.smackx.omemo.OmemoService.buildFreshSessionWithDevice(OmemoService.java:776)
        at org.jivesoftware.smackx.omemo.OmemoService.buildMissingSessionsWithDevices(OmemoService.java:815)
        at org.jivesoftware.smackx.omemo.OmemoService.encrypt(OmemoService.java:359)
        at org.jivesoftware.smackx.omemo.OmemoService.createOmemoMessage(OmemoService.java:537)
        at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:342)
        at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:315)
        at com.ef.network.jabber.xep.XEP0384.encode(xep0384.kt:186)
        at com.ef.network.jabber.Connection$send$1.invoke(Connection.kt:533)
        at com.ef.network.jabber.Connection$send$1.invoke(Connection.kt:33)
        at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)
2021-04-21 00:00:24.742 5706-6392/com.ef.messenger W/OmemoService: Could not load fingerprint of 01@akk.com:681702461
    org.jivesoftware.smackx.omemo.exceptions.NoIdentityKeyException
        at org.jivesoftware.smackx.omemo.OmemoStore.getFingerprint(OmemoStore.java:609)
        at org.jivesoftware.smackx.omemo.OmemoService.getUndecidedDevices(OmemoService.java:846)
        at org.jivesoftware.smackx.omemo.OmemoService.encrypt(OmemoService.java:361)
        at org.jivesoftware.smackx.omemo.OmemoService.createOmemoMessage(OmemoService.java:537)
        at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:342)
        at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:315)
        at com.ef.network.jabber.xep.XEP0384.encode(xep0384.kt:186)
        at com.ef.network.jabber.Connection$send$1.invoke(Connection.kt:533)
        at com.ef.network.jabber.Connection$send$1.invoke(Connection.kt:33)
        at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)

If there is a device with the same account in the list of devices, I can’t send a message, no matter what I do.
In my case, this is a pattern, that is, not once, even by accident)) I can’t send a message.
In order for me to send messages, I need to remove my own devices from the list, only then sending is possible. :sneezing_face:

@Ramazan_Abdulaev I think this will gone wonderful project i ever seen before this. Thanks man for sharing me this wonderful work :slightly_smiling_face:

1 Like

I’d like to know something.

public static PubSubManager getInstanceFor(XMPPConnection connection, BareJid pubSubService) {
    // CHECKSTYLE:ON:RegexpSingleline
        if (pubSubService != null && connection.isAuthenticated() && connection.getUser().asBareJid().equals(pubSubService)) {
            // PEP service.
            pubSubService = null;
        }

        PubSubManager pubSubManager;
        Map<BareJid, PubSubManager> managers;
        synchronized (INSTANCES) {
            managers = INSTANCES.get(connection);
            if (managers == null) {
                managers = new HashMap<>();
                INSTANCES.put(connection, managers);
            }
        }
        synchronized (managers) {
            pubSubManager = managers.get(pubSubService);
            if (pubSubManager == null) {
                pubSubManager = new PubSubManager(connection, pubSubService);
                managers.put(pubSubService, pubSubManager);
            }
        }

        return pubSubManager;
    }

PubSubService always null when I want to establish a session with my second device.
always returns my current device(PubSubService)!

in method getNode

 public Node getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAPubSubNodeException {
        StringUtils.requireNotNullNorEmpty(id, "The node ID can not be null or the empty string");
        Node node = nodeMap.get(id);

        if (node == null) {
            DiscoverInfo info = new DiscoverInfo();
            info.setTo(pubSubService);
            info.setNode(id);

            DiscoverInfo infoReply = connection().createStanzaCollectorAndSend(info).nextResultOrThrow();

            if (infoReply.hasIdentity(PubSub.ELEMENT, "leaf")) {
                node = new LeafNode(this, id);
            }
            else if (infoReply.hasIdentity(PubSub.ELEMENT, "collection")) {
                node = new CollectionNode(this, id);
            }
            else {
                throw new PubSubException.NotAPubSubNodeException(id, infoReply);
            }
            nodeMap.put(id, node);
        }
        return node;
    }

on the line info.setTo(pubSubService); pubSubService = null

Is this how it should be?
`

My suspicions were confirmed.
I extended XMPPTCPConnection and overrided method “createStanzaCollectorAndSend”.

class OmemoConnection(configuration: XMPPTCPConnectionConfiguration) : XMPPTCPConnection(configuration) {
    @Throws(SmackException.NotConnectedException::class, InterruptedException::class)
    override fun createStanzaCollectorAndSend(packet: IQ?): StanzaCollector? {
        val packetFilter: StanzaFilter = IQReplyFilter(packet, this)
        if (packet is DiscoverInfo) {
            if (packet.node?.contains(OmemoConstants.PEP_NODE_BUNDLES) == true)
                if (packet.to == null)
                    packet.to = user.asBareJid()
        }
        // Create the packet collector before sending the packet
        return createStanzaCollectorAndSend(packetFilter, packet)
    }
}

Now outgoing messages reach all my devices.