Smack OMEMO muc implementation support

aTalk has implemented most of the basic features supporting Omemo using smack 4.2.1. I have tested aTalk with Xmpp client conversations.

Currently aTalk is able to set up Omemo chat with conversations; sending and receiving of the omemo encrypted chat messages are working properly. However aTalk is facing problem in omemo support for muc. Below is the sendMessage() implementation for muc in aTalk. However when executing the following statement, smack throws an exception (log below)

encryptedMucMessage = omemoManager.encrypt(multiUserChat, msgContent);

(note: Message message is aTalk implementation is different from org.jivesoftware.smack.packet.Message)

I investigated the process how conversations setup the omemo muc. From the ejabberd xmpp server I can only detect the following stanza being send from conversations i.e. without the “attribute node=‘eu.siacs.conversations.axolotl.devicelist’”

2017-06-24 10:28:34.809 [debug] <0.23198.0>@ejabberd_receiver:process_data:284 Received XML on stream = <<"">>

With the modified conversations source, I managed to capture limited xmpp messages send/receive by conversations during startup as shown in below log.

While receive muc encrypted message

aTalk also failed to receive encryptedMucMessage sends from conversations (see log). I thinks it is because it cannot retrieve the omemodevice list for the muc members

However the message is received/sent OK with another conversation muc member.

I see there is a OmemoManager#buildSessionsWith(BareJid contact) for contact in setting up single user chat. How do I set up a conference chat session for omemo muc chat?

======== aTalk sendMessage() method for omemo muc chat ==========

public void sendMessage(Message message, OmemoManager omemoManager)
throws OperationFailedException
{
try {
assertConnected();
String msgContent = message.getContent();
org.jivesoftware.smack.packet.Message encryptedMucMessage = new org.jivesoftware.smack.packet.Message();

try {
EntityBareJid multiUserChat = mMultiUserChat.getRoom();
encryptedMucMessage = omemoManager.encrypt(multiUserChat, msgContent);
}
catch (CryptoFailedException | UndecidedOmemoIdentityException
| NoSuchAlgorithmException | InterruptedException
| CannotEstablishOmemoSessionException | SmackException.NotConnectedException
| SmackException.NoResponseException e) {
e.printStackTrace();
}
mMultiUserChat.sendMessage(encryptedMucMessage);
}
catch (NotConnectedException | InterruptedException e) {
logger.error("Failed to send message " + message, e);
throw new OperationFailedException("Failed to send message " + message,
OperationFailedException.GENERAL_ERROR, e);
}
}

========= Smack exception log for omemoManager.encrypt(multiUserChat, msgContent); ============

06-24 08:44:05.751 D/SMACK: SENT (0):

06-24 08:44:05.761 D/SMACK: RECV (0): The feature requested is not supported by the conference

06-24 08:44:05.771 D/SMACK: SENT (0):

06-24 08:44:05.821 D/SMACK: RECV (0): The feature requested is not supported by the conference

06-24 08:44:05.831 D/SMACK: RECV (0):

06-24 08:44:05.841 D/SMACK: SENT (0):

06-24 08:44:05.841 W/αTalk: [1] org.jivesoftware.smackx.omemo.OmemoService.refreshDeviceList() Could not fetch device list of chatroom@conference.atalk.org: org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPP error reply received from chatroom@conference.atalk.org: XMPPError: service-unavailable - cancel

                        org.jivesoftware.smack.XMPPException$XMPPErrorException: XMPP error reply received from chatroom@conference.atalk.org: XMPPError: service-unavailable - cancel

at org.jivesoftware.smack.StanzaCollector.nextResultOrThrow(StanzaCollector.java:2 56)

at org.jivesoftware.smack.StanzaCollector.nextResultOrThrow(StanzaCollector.java:2 08)

at org.jivesoftware.smackx.pubsub.LeafNode.getItems(LeafNode.java:196)

at org.jivesoftware.smackx.pubsub.LeafNode.getItems(LeafNode.java:189)

at org.jivesoftware.smackx.pubsub.LeafNode.getItems(LeafNode.java:139)

at org.jivesoftware.smackx.pubsub.PubSubManager.getLeafNodeProsodyWorkaround(PubSu bManager.java:346)

at org.jivesoftware.smackx.pubsub.PubSubManager.getLeafNode(PubSubManager.java:329 )

at org.jivesoftware.smackx.omemo.OmemoService.fetchDeviceListNode(OmemoService.jav a:435)

at org.jivesoftware.smackx.omemo.OmemoService.fetchDeviceList(OmemoService.java:45 2)

at org.jivesoftware.smackx.omemo.OmemoService.refreshDeviceList(OmemoService.java: 504)

at org.jivesoftware.smackx.omemo.OmemoService.buildOrCreateOmemoSessionsFromBundle s(OmemoService.java:605)

at org.jivesoftware.smackx.omemo.OmemoService.processSendingMessage(OmemoService.j ava:810)

at org.jivesoftware.smackx.omemo.OmemoService.processSendingMessage(OmemoService.j ava:787)

at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:209)

at net.java.sip.communicator.impl.protocol.jabber.ChatRoomJabberImpl.sendMessage(C hatRoomJabberImpl.java:813)

at org.atalk.android.gui.chat.conference.ConferenceChatTransport.sendInstantMessag e(ConferenceChatTransport.java:169)

at org.atalk.android.gui.chat.ChatController.sendMessage(ChatController.java:263)

at org.atalk.android.gui.chat.ChatController.onClick(ChatController.java:365)

at android.view.View.performClick(View.java:5181)

at android.view.View$PerformClick.run(View.java:20887)

at android.os.Handler.handleCallback(Handler.java:739)

at android.os.Handler.dispatchMessage(Handler.java:95)

at android.os.Looper.loop(Looper.java:145)

at android.app.ActivityThread.main(ActivityThread.java:5938)

at java.lang.reflect.Method.invoke(Native Method)

at java.lang.reflect.Method.invoke(Method.java:372)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1389 )

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1184)

06-24 08:44:05.851 D/SMACK: SENT (0): I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo5g0A7LjYAScYhG3CGbs93Q==grk0jA==</p ayload>

06-24 08:44:05.861 D/SMACK: SENT (0):

06-24 08:44:05.991 D/SMACK: RECV (0):

06-24 08:44:06.041 D/SMACK: RECV (0): 5g0A7LjYAScYhG3CGbs93Q==grk0jA==</p ayload>I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo

06-24 08:44:06.041 D/SMACK: RECV (0):

06-24 08:44:06.051 D/SMACK: SENT (0):

06-24 08:44:06.051 E/αTalk: [37] org.jivesoftware.smack.AbstractXMPPConnection.run() Exception in async packet listener

java.lang.NullPointerException: Attempt to invoke virtual method ‘int java.lang.Object.hashCode()’ on a null object reference

at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:746)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupantPresence(MultiUserChat.jav a:1667)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupant(MultiUserChat.java:1680)

at org.jivesoftware.smackx.omemo.OmemoService.getSender(OmemoService.java:1184)

at org.jivesoftware.smackx.omemo.OmemoService.access$000(OmemoService.java:106)

at org.jivesoftware.smackx.omemo.OmemoService$OmemoStanzaListener.processStanza(Om emoService.java:1229)

at org.jivesoftware.smack.AbstractXMPPConnection$4.run(AbstractXMPPConnection.java :1198)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)

at java.lang.Thread.run(Thread.java:818)

========= Smack log when receiving Omemo encrypted message during muc from conversations ============

06-24 08:12:40.741 D/SMACK: RECV (0): MwgrEiEFjOpAL8Rk1LGO9siB1h+nnL/qIbJ2pfy7SecSZPgxKV0aIQUUV5ApOiQnN cECsTvKWCH8wDMrQe4XtFTcxf88Tg61YSJiMwohBZRYbdpGHqgLARP8MvtRaWYet/KjoaYELN5qMpDK1 moNECoYACIw0hcyS2bFtdHinZKpAnubByCXeq2nzkcykWh68JWo5AzaJS6yGtFNZ1ooAnYiTxFIbVMyc d/1v20omZyyhQMwAQ==MwohBYdKaVS16Aof/OpK87Cpogp5UszF6qSYaLGvpptx7HRzEAEYACIwpZU6/Z dSKGR7H9oAzftTl+zVs00WSQR+JpaQO/u9NrXrb5NKrg5H1Aysq54tD5GNLXfaJ6EFz44=MwohBVPts29CYR1rBpL4w45rrqTrfCXEllki6D363gF3t8VbEAMYACIwx0vd+H YZk3kzRBKwtxnKe9oZNvBAi8OEjFYmYCw60whbl4f7WRIdN9Z6+IUFj3UqqUiEvpaIIi8=MwgfEiEFGQFL/66piWEridyeU0KsMS34/B/B+vOykndiRvVV4SYaIQUUV5ApOiQnN cECsTvKWCH8wDMrQe4XtFTcxf88Tg61YSJiMwohBe/VhE2upLjyhpHX4sc9s60s98CXdy12HdSFvI46W x5VECsYACIw+MLmq47BHFKIi/j2UAqzTWGpafOT6YfUJgED5m2F2m5NKrYlMPKMQkgPIqQaGhpwnK2hf 4Z2XWoomZyyhQMwAQ==MwgDEiEFOmOEA5w9J66CT8nG7LWl5x/Uyy8quduZS2EBzF8HolQaIQUUV5ApOiQnN cECsTvKWCH8wDMrQe4XtFTcxf88Tg61YSJiMwohBYakBsGB75jRG03R9fMYINhqZe4FSaoQG0xG0tFX3 xkJECsYACIwNlZdeJNP25nS7towrDIsDBlPcEWF2swJaOKMA74feroChSgsTfX15Jn4u35ei0WCAEJ7G BhO+hMomZyyhQMwAQ==MwhfEiEFfce91m91LPiK4a13nvGNPU/9EhNqXl6oiWS8TyN3zTgaIQUUV5ApOiQnN cECsTvKWCH8wDMrQe4XtFTcxf88Tg61YSJiMwohBXBVQIN5oLgT1OoYy1/7RfFRDoZVY7hoc35r/TKiL rVhECoYACIwIpwH38/F0uS/0uTj/EJbqufLKmXV/CHn1/2Fwnfm21FHCD+Q9olbVunQMMUvf3tWYIAvM sVs7CUomZyyhQMwAQ==hU6QBVDCIlQNg0yXLdIlVg==9JeJ FnC+yaEBGFnMwDJjIhI=I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo

06-24 08:12:40.941 D/SMACK: RECV (0):

06-24 08:12:40.951 D/SMACK: SENT (0):

06-24 08:12:41.011 E/αTalk: [33] org.jivesoftware.smack.AbstractXMPPConnection.run() Exception in async packet listener

java.lang.NullPointerException: Attempt to invoke virtual method ‘int java.lang.Object.hashCode()’ on a null object reference

at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:746)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupantPresence(MultiUserChat.jav a:1667)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupant(MultiUserChat.java:1680)

at org.jivesoftware.smackx.omemo.OmemoService.getSender(OmemoService.java:1184)

at org.jivesoftware.smackx.omemo.OmemoService.access$000(OmemoService.java:106)

at org.jivesoftware.smackx.omemo.OmemoService$OmemoStanzaListener.processStanza(Om emoService.java:1229)

at org.jivesoftware.smack.AbstractXMPPConnection$4.run(AbstractXMPPConnection.java :1198)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)

at java.lang.Thread.run(Thread.java:818)

============ Conversations log message during startup ==============

D/conversations: ### SMACK SENT:

D/conversations: hawk@atalk.org: retrieved own device list: [1796289951, 793357486]

I/conversations: AxolotlService (hawk@atalk.org): Building new session for hawk@atalk.org:793357486

D/conversations: AxolotlService (hawk@atalk.org): Retrieving bundle:

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: AxolotlService (hawk@atalk.org): Received PEP device list ([1691254927, 1077854796, 887665691]) update from leopard@atalk.org, processing


D/conversations: ### SMACK RECV:

D/conversations: AxolotlService (hawk@atalk.org): Received PEP device list ([793357486]) update from abc123@atalk.org, processing


D/conversations: ### SMACK RECV:

D/conversations: AxolotlService (hawk@atalk.org): Received PEP device list ([37379719, 816614937, 2087839431]) update from swan@atalk.org, processing


D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: AxolotlService (hawk@atalk.org): Received PEP device list ([1796289951, 793357486]) update from hawk@atalk.org, processing


D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: hawk@atalk.org: finished mam after 0(0) messages. messages left=true

D/conversations: ### SMACK RECV:

D/conversations: hawk@atalk.org: joining conversation chatroom@conference.atalk.org/hawk

D/conversations: ### SMACK SENT: iQG4BAEBCgAiGxxjbWVuZyA8Y21lbmcuZ21AZ21haWwuY29tPgUCWMc G8AAKCRAnJWERuLqvl9O1C/wJqTV4Dnj5OAAF8LRF9x5PoXX3AXqexutZXY5GY7T1HDNwhzm2mDsRFjA 30JyjFXIApDKh3ywgh3oBanwMXqPEt/5S78fABnz8fQdXg4xf51r512rGkM0tJJeVhBe1Ss904ZOg8C6 U+i2wt3UJMaU7rlVo2ElvVxI7raQgtGORO9+RmE+4tDPR4QkBTFzcDyLBh5OTEvsk5RykjsPXX4fAkXd kmv1fjrmge3/1y7YDawmvJc1X8IWo/nME5Hp9SnfwtuAeYK8qZR+zeC5YxgSEibQz9FjoEXecLwlul8K KCu/DPRono8FpgBrT8I21Ll2a51OyGAW19vZZvluPEwdEB+JfprXoy3hTnz1yyTHkPKatxX8QjtRVUIK TdG780XglifH35fswZIMuIpzfvqL0vMYNGu0W8QDLY5Qs7YJYFnJPLV4WyaV4Ja903EcB/NrTZlhoccf yUYt3sUvCbeXfybaoqxDyYqyT+uYe9jQSl9XY3yMGcz5B3pLFBgZoZAE==MkF9

D/conversations: hawk@atalk.org: running mam query to=chatroom@conference.atalk.org, start=2017-06-24T00:43:30.960Z, end=2017-06-24T02:29:46.564Z, order=NORMAL, catchup=true

D/conversations: ### SMACK SENT: urn:xmpp:mam:02017-06-24T00:43:30.960Z2017-06-24T02:29:46.564Z50

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK SENT:

D/conversations: hawk@atalk.org: fetching members for Group Chat

D/conversations: hawk@atalk.org: fetched muc configuration for chatroom@conference.atalk.org - [vcard-temp, http://jabber.org/protocol/muc, muc_hidden, muc_persistent, muc_membersonly, muc_nonanonymous, muc_moderated, muc_unsecured, urn:xmpp:mam:tmp, urn:xmpp:mam:0, urn:xmpp:mam:1]

D/conversations: ### SMACK RECV:

D/conversations: AxolotlService (hawk@atalk.org): Received preKey IQ packet, processing


E/conversations: AxolotlService (hawk@atalk.org): Error building session for hawk@atalk.org:793357486: org.whispersystems.libaxolotl.InvalidKeyException, Invalid signature on device key!

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: hawk@atalk.org: finished mam after 0(0) messages. messages left=true

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: ### SMACK RECV:

D/conversations: hawk@atalk.org: retrieved members for chatroom@conference.atalk.org: [leopard@atalk.org, swan@atalk.org]

D/conversations: ### SMACK RECV:

W/art: Suspending all threads took: 9.797ms

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK RECV:

D/conversations: deleted file /storage/emulated/0/WhatsApp/.Shared/H5uM7RD3qo6NN+f5MEVvNam88Pt8VjNXoPgIsOmvJ4 k=.enc.tmp

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK RECV:

W/art: Suspending all threads took: 14.015ms

D/conversations: ### SMACK SENT:

D/conversations: ### SMACK RECV:

Hi!

In order to send messages to a MUC, you have to use the OmemoManager.encrypt(MultiUserChat, String) method. In your example you used OmemoManager.encrypt(BareJid, String), which does not work. It might be a good idea to unify this in the future.

Please note, that you can only send OMEMO messages in MUCs that are non-anonymous and only if you have all members added to your roster.

Edit: Could you tag future questions regarding OMEMO with the omemo tag?

Many thanks. It is my mistake. Actually the mMultiUserChat is already the correct MultiUserChat object. After changes to

encryptedMucMessage = omemoManager.encrypt(mMultiUserChat , msgContent);

sending muc omemo encrypted message is now OK.

However I still have problem in receiving omemo encrypted muc message from conversations. The log is attached in my previous message i.e.

========= Smack log when receiving Omemo encrypted message during muc from conversations ============

In aTalk implementation, I have a small routine (doHandleOMemoPressed as below) when user select the OMEMO option for single user Chat. In which I have included

mOMemoManager.buildSessionsWith(bareJid);

Is this statement necessary when user want to set up chatSession to send Omemo encrypted message?

If so, is there an equivalent for MultiUserChat session initialization; as I am unable to find any for Omemo muc session setup.

Note, that you can only send OMEMO messages in MUCs that are non-anonymous:

Thanks for the reminder, actually aTalk has already implemented the method below to only enable the OMEMO option if true.

private boolean isOMemoSupport()

====== doHandleOMemoPressed =====

if (mDescriptor instanceof Contact) {
BareJid bareJid = ((Contact) mDescriptor).getJid().asBareJid();
fingerPrints = mOMemoManager.getActiveFingerprints(bareJid);
for (Map.Entry<OmemoDevice, OmemoFingerprint> entry : fingerPrints.entrySet()) {
omemoDevice = entry.getKey();
fingerPrint = entry.getValue();
if (!mOMemoManager.isDecidedOmemoIdentity(omemoDevice, fingerPrint)) {
aTalkApp.getGlobalContext().startActivity(
OmemoAuthenticateDialog.createIntent(mOMemoManager, omemoDevice));
// mOMemoManager.trustOmemoIdentity(omemoDevice, fingerPrint);
}
}

if (mOMemoManager.isTrustedOmemoIdentity(omemoDevice, fingerPrint)) {
activeChat.setChatType(ChatFragment.MSGTYPE_OMEMO);
mOmemoDevice = omemoDevice;
}
else {
activeChat.setChatType(ChatFragment.MSGTYPE_OMEMO_UA);
}

try {
mOMemoManager.buildSessionsWith(bareJid);
}
catch (InterruptedException | CannotEstablishOmemoSessionException
| SmackException.NotConnectedException
| SmackException.NoResponseException e) {
e.printStackTrace();
}
}

// =======================

/**

  • Check if OMEMO is supported by current chatTransport

  • @return true if OMEMO is supported on current chatTransport
    */
    private boolean isOMemoSupported()
    {
    boolean serverCan = false;
    boolean entityCan = true;

    mChatTransport = activeChat.getChatSession().getCurrentChatTransport();
    pps = mChatTransport.getProtocolProvider();
    XMPPTCPConnection connection = pps.getConnection();
    mDescriptor = mChatTransport.getDescriptor();
    mOMemoManager = OmemoManager.getInstanceFor(connection);

    try {
    DomainBareJid serverJid = connection.getServiceName();
    serverCan = OmemoManager.serverSupportsOmemo(connection, serverJid);

    if (mDescriptor instanceof ChatRoom) {
    EntityBareJid chatRoom = ((ChatRoom) mDescriptor).getIdentifier();
    entityCan = mOMemoManager.multiUserChatSupportsOmemo(chatRoom);
    }
    else {
    String contactId = ((Contact) mDescriptor).getAddress();
    Collection resources = ((Contact) mDescriptor).getResources();
    for (ContactResource resource : resources) {
    String contactJid = contactId + “/” + resource.getResourceName();
    FullJid contactsResourceJid = null;
    try {
    contactsResourceJid = JidCreate.entityFullFrom(contactJid);
    entityCan = mOMemoManager.resourceSupportsOmemo(contactsResourceJid);
    break;
    }
    catch (XmppStringprepException e) {
    e.printStackTrace();
    }
    }
    }
    }
    catch (XMPPException.XMPPErrorException | SmackException.NoResponseException
    | InterruptedException | SmackException.NotConnectedException e) {
    e.printStackTrace();
    }
    return serverCan && entityCan;
    }

Investigate further on muc omemo message sending. Below is the aTalk log upon executed mMultiUserChat.sendMessage(encryptedMucMessage) statement.

In normal muc operation after muc.sendMessage(), the xmpp server actually relays the earlier sent message to all the conference members including the sender himself. It appears that, smack omemo is currently not handling this relay message.

Not sure if Smack has any plan to include support to process this relay message, or leave it to application layer to decrypt the message for display.

aTalk currently is not handling the relay omemo encrypted message, so it displays text of the omemo encryptedMessage in the chat window.

“I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo”

Note: xmpp server will also relays any muc history messages that are sent from other members while the user was offline

Below is the an extraction of aTalk in handling the muc relay messages in plain mode.

===========================

@Override
public void processMessage(org.jivesoftware.smack.packet.Message msg)
{
if (msg == null)
return;

Date timeStamp;
DelayInformation delayInfo = msg.getExtension(DelayInformation.ELEMENT, DelayInformation.NAMESPACE);
if (delayInfo != null) {
timeStamp = delayInfo.getStamp();

// This is a delayed chat room message, a history message for the room coming from
// server. Lets check have we already shown this message and if this is the case
// skip it otherwise save it as last seen delayed message
if (lastSeenDelayedMessage == null) {
// initialise this from configuration
String timestamp = ConfigurationUtils.getChatRoomProperty(mProvider,
getName(), LAST_SEEN_DELAYED_MESSAGE_PROP);

try {
lastSeenDelayedMessage = new Date(Long.parseLong(timestamp));
}
catch (Throwable ex) {
ex.printStackTrace();
}
}

if (lastSeenDelayedMessage != null && !timeStamp.after(lastSeenDelayedMessage))
return;

// save it in configuration
ConfigurationUtils.updateChatRoomProperty(mProvider, getName(),
LAST_SEEN_DELAYED_MESSAGE_PROP, String.valueOf(timeStamp.getTime()));
lastSeenDelayedMessage = timeStamp;
}
else {
timeStamp = new Date();
}

// for delay message only
Jid jabberID = null;
MultipleAddresses mAddress = msg.getExtension(MultipleAddresses.ELEMENT,
MultipleAddresses.NAMESPACE);
if (mAddress != null) {
List<MultipleAddresses.Address> addresses = mAddress.getAddressesOfType(MultipleAddresses.Type.ofrom);
jabberID = addresses.get(0).getJid().asBareJid();
}

String msgBody = msg.getBody();
if (msgBody == null)
return;

ChatRoomMember member;
int messageReceivedEventType = ChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED;

Jid entityJid = msg.getFrom(); // chatRoom entityJid
Resourcepart fromNick = entityJid.getResourceOrNull();

// when the message comes from the room itself, it is a system message
if (entityJid.equals(getName())) {
messageReceivedEventType = ChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED;
member = new ChatRoomMemberJabberImpl(ChatRoomJabberImpl.this, getName(), getName());
}
else {
member = members.get((EntityFullJid) entityJid);
}

// sometimes when connecting to rooms they send history when the member is no longer
// available we create a fake one so the messages to be displayed.
if (member == null) {
member = new ChatRoomMemberJabberImpl(ChatRoomJabberImpl.this, fromNick.toString(),
jabberID.toString());
}

if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled())
logger.debug("Received from " + fromNick + " the message " + msg.toXML());
}

Message newMessage = createMessage(msgBody);
if (msg.getType() == org.jivesoftware.smack.packet.Message.Type.error) {
if (logger.isInfoEnabled())
logger.info("Message error received from: " + fromNick);

XMPPError error = msg.getError();
Condition errorCode = error.getCondition();
int errorResultCode = ChatRoomMessageDeliveryFailedEvent.UNKNOWN_ERROR;
String errorReason = error.getConditionText();

if (errorCode == XMPPError.Condition.service_unavailable) {
Condition errorCondition = error.getCondition();
if (Condition.service_unavailable == errorCondition) {
if (!member.getPresenceStatus().isOnline()) {
errorResultCode = ChatRoomMessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED;
}
}
}
ChatRoomMessageDeliveryFailedEvent evt = new ChatRoomMessageDeliveryFailedEvent(ChatRoomJabberImpl.this,
member, errorResultCode, errorReason, new Date(), newMessage);
fireMessageEvent(evt);
return;
}

// Check received message for sent message: either a delivery report or a message
// coming from the chaRoom server. Checking using nick OR jid in case user join
// with a different nick.
if (((getUserNickname() != null) && getUserNickname().equals(fromNick)) || ((jabberID != null)
&& jabberID.equals(getAccountId(member.getChatRoom())))) {
// message delivered
ChatRoomMessageDeliveredEvent msgDeliveredEvt = new ChatRoomMessageDeliveredEvent(
ChatRoomJabberImpl.this, timeStamp, newMessage,
ChatRoomMessageDeliveredEvent.CONVERSATION_MESSAGE_DELIVERED);

msgDeliveredEvt.setHistoryMessage(true);
fireMessageEvent(msgDeliveredEvt);
}
else {
// CONVERSATION_MESSAGE_RECEIVED or SYSTEM_MESSAGE_RECEIVED
ChatRoomMessageReceivedEvent msgReceivedEvt = new ChatRoomMessageReceivedEvent(
ChatRoomJabberImpl.this, member, timeStamp, newMessage,
messageReceivedEventType);

if (messageReceivedEventType == ChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED

&& newMessage.getContent().contains(getUserNickname() + “:”)) {
msgReceivedEvt.setImportantMessage(true);
}

msgReceivedEvt.setHistoryMessage(delayInfo != null);
fireMessageEvent(msgReceivedEvt);
}
}

=========== aTalk captured log on mMultiUserChat.sendMessage(encryptedMucMessage) ============

06-25 02:46:36.255 D/SMACK: SENT (0):

06-25 02:46:36.275 D/SMACK: RECV (0): http://jabber.org/protocol/muc#roominfo3

06-25 02:46:36.405 D/SMACK: RECV (0):

06-25 02:46:36.425 D/SMACK: SENT (0):

06-25 02:46:36.605 D/SMACK: SENT (0):

06-25 02:46:36.655 D/SMACK: RECV (0): 01creation@001474:502968:279177creation@001474:502968:279 177BT18u6ztLTVRNjP22kiGm+MKkAJOEIxQftz6x2u5qxsJ

vsZjh0Q/tLFRvoFCY3vv6XBnxlh0y/DxS7E lP/LKYfWn7af9XPEbFSg5KlxrqFdAGPKwhuhU6sQ6

4SRNPpdwAA==

BRzwoKsHyjwWgKTHRjnk6fYq4R77umIEP5Bn58Zf7n 9a

BUoJudpg45xQVf72XHRvP/n8+3h0Hpu+4KJdxsXIARFZ

Bb9crnWTCd1JjZst7IVusOZF+TMMHJSgyraIq6Mft1VV

BQLNPChjv4mYsJlJ1n7bF3vnQs23uqZVkIWrfLN7FIYE

Be9qu9BcxV7BtF8wZZCUohcDfZwUaHTw6IuIXsyuNZM7

Bchdh8/Ppipw/Rvnm+NgANjpSaXyWvaHT8hcTtdhRXYZ

BdWYz7pwc42IAHzThu5GKec3T1W/BZvHc4GJeBX6+Txl

BTQu1M8kxFNy8HLy27Pewkey6J1n5qxwJ8Am9+XUM75u

BYbEU1kDO1R3XFmH5KgJghGME6JvE2UEN4ozfkq8ugsA

Bfi1vvSpSN7/ZODapSdn1IiKJZ02mejCqm6SU9wSURtn

BWAVlbXbCEJzaSWf4BudHnN0WhibWDCqtJdnpcOceoxC

BSJeSjKVOdi7DtJUIqFSqxN9YfpDdbTHiDeRIDAOKM9B

BdU2hQjZxBgDIj5Bx5V+bS/auq0vbD7Yx4qBszI4fJMw

BZndDAOyIj3yS5CJojKsfhLfIsIXzcWknmvSOEGlwcJN

BZ+nHS9ej09TgQL85U/85s537AmZDaGeeXlUhQrRBONm

Be8U2LaV9NWCZlyfe0r+a2M4RuVv1wt/qGNqMgNaVhRg

Bb8CzNoH3TA/nuwqOGz8han+6VUEELSSEO6m9J9VA8kh

BYdeKEU1i6PYmN0VrkmA8UrgPkx4PMehqDcas+jRtXAW

BfxvMz62NBoCzSiGRjckKzzsp8AMlIFuaR8ICfteYWtg

BcjJfWvjOXP7QTLIkEDoJXhPzMome8Wk/srlaR+kyl4h

BdoqW7ceIWMmjB87P/9QnV1R83LE5nvZwHQgT3aXDUM2

Bex4T2bBNKrHWqDtBlU6y5vCqXxMAgsqIS77LMrwo6RT

BWT+7XktWKu2n/aDxezmz7DZMwGF1iqDDGwo0NqGJ2dc

BTWGSCojuuerDCAkN6iIYWfpxrNWZ03hFtZ5WEluAPxT

Bcbh03G68+jlrb2SgjTRLuK4YVwiTHZ9THHOzQrJK8Um

BbZxgq8DLaPaJy7yJuPJKlvFTN98ulD5XxS2xYjuuaI9

<preKeyPublic p

06-25 02:46:36.905 D/SMACK: RECV (0): reKeyId=‘270’>BfDgjX3KfDnlUJ+bzySqI+pTLq7h621HOuclViSjjYxs

BfNwr2nXJg2TRsRwX+bKI7y4thvygLvfmTPso77A72Fg

BfQbXS6h+4sD1EaHpMrGxRwZ8MOfrMOcliyjCkiK9/Ax

BU12kpG8hktSpuNHuTsDBMAAHtB0/JTxToJvfZyuc3kO

BUrhb/+vuI7pKqozuS5UXxdAY2lEgDGJ8KmktP49aIcG

BbLFPSAXyl3WdJGG8mq4qv2ivAGEkKCXSM7fo9KXHkI0

Bas2aph9gOpX2F+h6KqCjQmxcurbSI6bNApfK/jk9CQU

BRsbB3Yj/zFNsI1CODxhSG5/U9mONB6CcOjuvrdnKwIK

BcvR/IKdNKrQjoL50L3sgOxI97mlcVelQ2WK1EUbhCQ5

BVgD9DGAarzOcKaxm01LLhOKF+WHW+d2CnuBUrSWjOdU

BaEHkxH1NjOrjEJ03lrypUNM9xQaMauajG8mTUk1YCoz

BRAc4cGchLznkrK4KNJngfp9OKgGTnxqLMlgMVLT4JBt

BcPCqyxgjathsulDuPrTr364DtfmHyFiOqGhIzf7Iu4U

BWYakTOz2b+kPx8mPvrnaP+ZpaEV95Mh0eyZjnNy71BL

Bfbuo18PN/ZXbcv61gTpeBQVvaXttdKTpouBO3kixW87

BeVaG5X2bPkce/NcyU3EKoKIbirCfJtg0ayMiNimbrxx

BcZ9D2zjpTq/XOdyo++804mgCa8YNUBYsBcKtc9lqM4U

BdqreKbGQoXse3G5o9f0QDkSpMK/T7kBemt9Rz0a3pFx

BRu/GE8YXiUFmPJT04sOi9B112QIxGEY11cTGHOp7b8Q

BY6XFgeSAvhrbciBBOOSu1E2vlU0JLj1McvPnpWjnnwA

BbPMNn7EQ6FN8aW2d1tCYgGbdvUSaUnVPJiVNMExhgdA

BeN2wTJvgebQAXcxf1/bqtyuthivu4BW1lWSlmQONHdn

BWkgro19EgG6xmrdDC7RnON2GD7eRcYNjKFIyeRZ1q9f

BRl/34Sac7KVplEQNOerzb+eA0rMS4gTSFpOH+H9TdhX

BTHl1fPmXT90lGlBFKG7q4pFAF3xkk08ork281hugRtM

BRY0rUFtdXtv5Lh48dcdGJmc+BGsc0AvLqVL6LTCDIQP

BeYbDyyVl7UnutHBRRw0LG5GMff26XH0sw/eI4xr16s6

BQCM3QauBOknumiskN1oZ//vMIWFJruigMnft/h7Z853

BdjURj4/1bd/txWsaCe/rBZSag1IbhFZ5nOQah6+uox3

BQ8e8J8XvUP9+AUocCJvX7rgZoO6BYLA+nXH4FQ/ucEh

BUkjZGQ6R5P2xD7vdot3uoT5ciJtruYHbtv78BaVqV9X

BQ9uGG24xnVG4BlVFganuHpSlbXgsGvW9FfGVZhsMtNq

BU3auCokx8JERygRK7hJBccO8QYg7YZ8EgcFHCN+uO89

BZ2axfkzekSJpnFU6VTVd0Ayti6OQNGtYJ73DLVDzT0Q

BTP++Npxk6PuD6y41b1T4sO6XzFNZSy426F6UmjjNDx0

BRQKyLIZFcvVgAJ28NET21TDlnJ+EYzZi63lIwLyrn1h

BXZRcCCiDtrzjPj9RavpJ33DEnmddrW8IkHGC6vbFCpP

BcNVxbV7JXM8v0OpTAryi/Yb8w+7GUCWPFR6+o/gsD1m

BTkuz+r+dBBXVjKROt90gLlHwgsWdgSj9cJeGdOUg4JR

BRML799wp7aj7bp5u3QclXL8EjBAmWuMUqsHyh9qLsZ3

BZtoSL4XCBQY9YGNhDr/7mVoPL2jIyBKtOE+8gHpGpck

BUe4Y4WpizDsbF826VpFMMBGtHoqby55AknPptmw3PhL

BRXefsyt8oBi6Dm9N6CRIhOVps/QJNs1iI6va1CSln9e

BZ2sPibDnZqtfKgOlhXTTBLZshLq9i8Me5d1cFpb2WgR

BV4BMAk6vDNeBIgBJZYQf/1WVW3KZ7sXw8bzgmp0SIFR

BaeW0uFUgE2DWLczGji3+qeJGWFutR3noVrb8He

06-25 02:46:37.345 D/SMACK: RECV (0):

06-25 02:46:37.365 D/SMACK: SENT (0):

06-25 02:46:40.705 D/SMACK: SENT (0): I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemoMwgVEiEFQJPj6iIQ5Oic9FO/sjpmiMCWnVnCE85EyB97ySta41YaIQXiVJYpilf5 SjOSNYOzM9osNnaDAFWdwAh9bTovBWYwCSJiMwohBeQBRH9I6upyJ/PAHz8EulnnnKEWie9vBoZATopu tQQxECwYACIwzgmDMMIURqgvgwBT+9Uxpb7tT1+jmOxKVfcGyIB//tuIRMaXwVhieyEKJkoTsXB499SP iCr+f78oADABMwohBb7kzCqNoah9AtMsckU/6+wh7Q4+Vd7BsCi3hYb5SnxHEBYYACIwDoXrkNp wsYVc/wkzylfT5td3AZLiy06mIh98JJ8THLiN6P3KYjY4/JrA2bHA21y1ESezmGRGUmU=MwohBUr06WuOv/jbRi73gUFNvTJ14kJEYv10mYI47wDLz7A/EAwYACIwHXJ49w Xp/6iSqeOhsodr5UALxq7BImbOha0tUPhlVop34wVtNX/gY3U/K8YlBgIgiDytX0N2yk0= ZpqckHofiDbFMFLHezIOMw==bUYFGw==

06-25 02:46:40.725 D/SMACK: RECV (0):

06-25 02:46:40.835 D/SMACK: RECV (0): MwgVEiEFQJPj6iIQ5Oic9FO/sjpmiMCWnVnCE85EyB97ySta41YaIQXiVJYpilf5 SjOSNYOzM9osNnaDAFWdwAh9bTovBWYwCSJiMwohBeQBRH9I6upyJ/PAHz8EulnnnKEWie9vBoZATopu tQQxECwYACIwzgmDMMIURqgvgwBT+9Uxpb7tT1+jmOxKVfcGyIB//tuIRMaXwVhieyEKJkoTsXB499SP iCr+f78oADABMwohBb7kzCqNoah9AtMsckU/6+wh7Q4+Vd7BsCi3hYb5SnxHEBYYACIwDoXrkNp wsYVc/wkzylfT5td3AZLiy06mIh98JJ8THLiN6P3KYjY4/JrA2bHA21y1ESezmGRGUmU=MwohBUr06WuOv/jbRi73gUFNvTJ14kJEYv10mYI47wDLz7A/EAwYACIwHXJ49w Xp/6iSqeOhsodr5UALxq7BImbOha0tUPhlVop34wVtNX/gY3U/K8YlBgIgiDytX0N2yk0= ZpqckHofiDbFMFLHezIOMw==bUYFGw==I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo

06-25 02:46:40.955 D/SMACK: RECV (0):

06-25 02:46:40.965 D/SMACK: SENT (0):

Hi!

There was another bug in the code causing your issue when receiving MUC messages. I created a fix for that.

Calling buildSessionsWith() is usually not necessary. I added the method to enable a client to force session creation in case something goes wrong, but smack-omemo should build session by itself when needed.

Your other issue regarding sent MUC messages showing up on sender side as encrypted messages can be fixed by your client implmenting XEP-0300 EME (Explicit Message Encryption). Unfortunately it is forbidden for the sender to encrypt the message for themselves, so you have to “manually” hide encrypted messages using xep-0300.

Hope I could help you

Reading though your code I wondered about your spelling of OMEMO. OMEMO has nothing to do with “Memo”. It stands for “OMEMO Multi End Message and Object encryption”

Btw: is your code published somewhere? I’d love to take a look

After more in-depth testings on Omemo encrypted receive failures . Below are my observations that hopefully explain all the problems encountered thus far.

I modified the aTalk source to include a private getMessageContent() method i.e.:

// ===============================

/**

  • Return the corresponding message.body for either:
  • a. omemo encrypted muc message or
  • b. normal muc chat message
  • @param message
  • message
  • @return the extract message.body
    */
    private String getMessageContent(org.jivesoftware.smack.packet.Message message)
    {
    ClearTextMessage decrypted = null;
    XMPPTCPConnection xmppConnection = mProvider.getConnection();

OmemoManager omemoManager = OmemoManager.getInstanceFor(xmppConnection);
if (OmemoManager.stanzaContainsOmemoElement(message)) {
// BareJid sender = message.getFrom().asBareJid();
// MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(xmppConnection);
// MultiUserChat muc = mucm.getMultiUserChat(sender.asEntityBareJidIfPossible());
// sender = muc.getOccupant(sender.asEntityFullJidIfPossible()).getJid().asBareJid();

EntityFullJid nick = (EntityFullJid) message.getFrom();
MultiUserChatManager mucMgr = MultiUserChatManager.getInstanceFor(xmppConnection);
MultiUserChat muc = mucMgr.getMultiUserChat(nick.asEntityBareJidIfPossible());
BareJid sender = muc.getOccupant(nick).getJid().asBareJid();
try {
if (sender != null)
decrypted = omemoManager.decrypt(sender, message);
}
catch (InterruptedException | NoResponseException | NotConnectedException
| XMPPErrorException | CorruptedOmemoKeyException | NoRawSessionException
| CryptoFailedException e) {
e.printStackTrace();
}
}
return (decrypted != null) ? decrypted.getBody() : message.getBody();
}

// ==========end of method ===========

and change the statement i.e. String msgBody = msg.getBody(); in

public void processMessage(org.jivesoftware.smack.packet.Message msg)

to use getMessageContent() instead i.e


=== new code ===

String msgBody = getMessageContent(msg); // msg.getBody();
if (msgBody == null)
return;

With the above modifications, then aTalk is able to receive and decrypt the omemoEncrypted muc messages properly for display using getMessageContent() method; which are sent from conversations client
However smack OmemoService() still throws similar exception as shown in the error log below. If I modified the getMessageContent() method to use below code to obtain sender, then I experience the same exception being thrown when executing the below statement.

sender = muc.getOccupant(sender.asEntityFullJidIfPossible()).getJid().asBareJid();

======= get sender code that will throw exception ============

// BareJid sender = message.getFrom().asBareJid();
// MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(xmppConnection);
// MultiUserChat muc = mucm.getMultiUserChat(sender.asEntityBareJidIfPossible());
// sender = muc.getOccupant(sender.asEntityFullJidIfPossible()).getJid().asBareJid();

With these observations, I concluded that the exception throw is actually caused by

at org.jivesoftware.smackx.omemo.OmemoService.getSender(OmemoService.java:1184)

which has similar code as above i.e.

private static OmemoDevice getSender(OmemoManager omemoManager, Stanza stanza) {

OmemoElement omemoElement = stanza.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
BareJid sender = stanza.getFrom().asBareJid();
if (isMucMessage(omemoManager, stanza)) {
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
MultiUserChat muc = mucm.getMultiUserChat(sender.asEntityBareJidIfPossible());
sender = muc.getOccupant(sender.asEntityFullJidIfPossible()).getJid().asBareJid();
}
if (sender == null) {
throw new AssertionError(“Sender is null.”);
}
return new OmemoDevice(sender, omemoElement.getHeader().getSid());
}

// ====================================================== //

====== OmemoEncrypted muc message sending ============

As for the muc message sending, the smack error code are captured below in particular:

06-25 17:01:40.609 I/αTalk: [28] org.jivesoftware.smackx.omemo.OmemoService.processReceivingMessage() There is no key with our deviceId. Silently discard the message. ### i.e. so is aTalk doing the same; return if getMessageContent returns null

The above smack log message properly has explained everything. Any omemoEncrypted muc message sending from a sender is actually being relayed by the server back to the sender as received message for decrypt and display in the sender muc chat window. After checking through the sid and rid’s in details in encrypted element for and etc

I realizes that the elements actually do not include the sender key, hence explained the above error log message when omemoService trys to decrypt the message. In all encrypted muc chat implementation, the encryption algorithm should also include the sender key and/or any decryption information, so the relayed message from the server can be properly decrypted by the sender for display on the chat window.

============ aTalk error log for Smack OmemoService =============

06-25 17:01:40.609 I/αTalk: [28] org.jivesoftware.smackx.omemo.OmemoService.processReceivingMessage() There is no key with our deviceId. Silently discard the message.

06-25 17:01:53.089 D/SMACK: RECV (0): <stanza-id

06-25 17:01:53.089 D/SMACK: RECV (0): by=‘chatroom@conference.atalk.org’ id=‘1498381252059664’ xmlns=‘urn:xmpp:sid:0’/>MwohBeZsbTO5lzoexcXf7PLQqnTl4rvin7sAbug3O6TUUBQNEAAYASIw3LkSrJ2 L+wRCdI2pZR0+d6WyHEwkt53Lvk2LFw5pLhZeumDR159g7MNOGZmrANqW8ldgCdevIqI=MwohBVPts29CYR1rBpL4w45rrqTrfCXEllki6D363gF3t8VbEBoYACIw8M5DTW /7qggbIeAPpOfOsOwblOuyWhXUDYVZVIe+ge0iDoTfeectL9PS9lKkQOTEFCRe5mKJe3M=MwgDEiEFOmOEA5w9J66CT8nG7LWl5x/Uyy8quduZS2EBzF8HolQaIQUUV5ApOiQnN cECsTvKWCH8wDMrQe4XtFTcxf88Tg61YSJiMwohBYakBsGB75jRG03R9fMYINhqZe4FSaoQG0xG0tFX3 xkJEEMYACIwSMrkYKoK8dyokEfU7rP2/XULD7MS9T/R3gCwUdyNv1VUeQ7e5X5xhu0wo3hbCmte7zDtl 4AfvhcomZyyhQMwAQ==n0Pv/RhXIUoG8MBPX48Cgw==I7g= I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo

06-25 17:01:53.109 E/αTalk: [46] org.jivesoftware.smack.AbstractXMPPConnection.run() Exception in async packet listener

java.lang.NullPointerException: Attempt to invoke virtual method ‘int java.lang.Object.hashCode()’ on a null object reference

at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:746)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupantPresence(MultiUserChat.jav a:1667)

at org.jivesoftware.smackx.muc.MultiUserChat.getOccupant(MultiUserChat.java:1680)

at org.jivesoftware.smackx.omemo.OmemoService.getSender(OmemoService.java:1184)

at org.jivesoftware.smackx.omemo.OmemoService.access$000(OmemoService.java:106)

at org.jivesoftware.smackx.omemo.OmemoService$OmemoStanzaListener.processStanza(Om emoService.java:1229)

at org.jivesoftware.smack.AbstractXMPPConnection$4.run(AbstractXMPPConnection.java :1198)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)

at java.lang.Thread.run(Thread.java:818)

Hi!

Instead of manually decrypting received messages, it is advised, to register listeners instead. There is the OmemoMessageListener for single messages, as well as the OmemoMucMessageListener for MUC messages.

Yes, I have already included both the OmemoMessageListener for single messages, as well as the OmemoMucMessageListener for MUC messages in aTalk code.

The processMessage() code is the existing aTalk code that are yet to be ported to use smack MessageListener. However I need to understand how normal Smack MessageListener handles all the conditions that are enlisted in the aTalk processMessage() before confirm using it.

I checked the muc omemo encrypted sending messages, it also did not include the sender as one the recipients . If this is how everyone implementation in omemo muc chat encryption when sending message, then atalk would also have to modify not to use this approach as proposed earlier.

currently aTalk source is not in the public domain, as I have still need to clean up the source.

My first idea would be to create a modified processMessage method, which takes the output of the omemoMessageListeners. The listeners return the original message with all elements (delayed etc.), as well as a message containing only a body witht the decrypted message.

The OMEMO protocol forbids a device to encrypt a message for itself, so if a jid has only one device associated with it, then the jid gets not added with a .

Thanks for info. Just implemented a solution for aTalk to display its own muc omemo encrypted sending message without using the server relayed muc encrypted message since it contains no sender . aTalk muc is now tested working for both the sending and receiving muc omemo encrypted messages with the conversations client.

1 Like

Thats great news! Can’t wait to try it out .
Please let me know about any missing features, convenience methods etc. I’m always glad to get feedback from client devs .

Need to clean up some omemo UI and to implement sqlite storage for atalk before another new release.

I observed another problem with reply timeout in id=J8c7V-110, as the server replies after ~6S elapsed time, longer than the smack default wait time of 5S. Not sure who is responsible to change the smack default time in this case.

=========== aTalk log for reply timeout for omemo ================

06-27 13:08:22.633 D/SMACK: SENT (0):

06-27 13:08:22.813 D/SMACK: RECV (0):

06-27 13:08:22.813 D/SMACK: SENT (0):

06-27 13:08:22.823 D/SMACK: RECV (0):

06-27 13:08:22.823 D/SMACK: RECV (0): 11creation@001498:377059:657681creation@001498:377059:657 681

06-27 13:08:23.533 D/SMACK: SENT (0): <iq to=‘leopard@atalk.org’ id=‘J8c7V-110’ type=‘set’>Bbs90tkJ9FYguyFS2MVKwyEZrSdB/mhrSqmrRqEXgTlV</signedPreKeyPu blic>gw+H/xmpa4rA2JFO9nvkpjsLkyhtljOm35eIieYHoUUSrLKmlQWv BeUgCrK4QFCUzbaRMQGw/6+/Vg0iNh/9DA==BesU7el fJqn7MW2SiJcPkpxQvl5pZ4jlRMpcfWDRmcN5BajqnVzetsCoD/jciCAfIrNbKbDG+yVX6PbywSVo/PZCBVJSy/DTEhwOxupSReiwYABa2lM71aXD14P3l4PMK342BTQIMD4f1zya6BCO+lK0lYRxNwEUi5e/o6upTdykM7g0BWr9rVIy+sLxv0qRnv3jm+7jpTA9L2tvhZksscE9Z0k7Ba6eV0h5JztHex1i6qp6e72Y09ePGay4hmrkCasCPSJKBW//CPqkTPDgBWOp3obtKuFsFOb778sCUEZ+a5REX41YBR/0apGyARupl/NtylqTCxfBlMO94x8TsZtPNCVhR7R3Bf9NVman9RKLvbGLjNOAlaqsRtvkDmgZTKcK0Y7AGHcDBWQNlrXaVKJ7ETKTLt2kiXnyG3dMvODHtCnNqyWm5VYeBbQGyVxCLY+oEZ4gNIuP3ttwEd+OJRFVImRNVSuVKAoOBbLRcReHldk3fb9p8OwtpI/KWiTy6SJ4hNDfLNA0MFo+BRD1gVCndzLk5ylUcfwrSj6/pFQ+3gkMX3C2URaTffhVBbPtn0E2PqBu6VdyYtj7f6+PI38RHVjOLC6JMkZYLz1EBajRHaI6aKddbWtbGJAA/yEDgXdVyRuUNVfjNTx0lkgIBSwa0Kmwm6K5PkeJ0VbZadjNVmY2mH3prP6dCSBFyJJhBaVdpUn3TsEG61pO9XOo2OeJo+LL6apq0ctUc2TMk9gYBS0SEpYY6/0mbfqzvuaNU3GwtYY6eK01o0sAz7Ee1RUeBTwMTKTlF2x/QDEv3ZypPuM0XrCHMShVTbbymDglzL8BBcf9z3mitDd6DKF/0VEDSAl1OZ9sbFqJOLR/ytNezmQfBSKYAM+Ua38D6K1cCAb9vdUkEa+M6mHedGPjLovE+f8cBWZECbmzaX5FgRHrpYNVKqf3Bo5ao9STehfpL0uobis1BZxwYIW6iFnDKj1Jzi6gDd4VssPejaL08ywqV76fFu5PBRW0Gq/bF65GsNtY1InoJbwaOX3Qz6CC3vxRvu2m67R4BXhTZ1qMG0pKT3i8g9Xu8RK+bLcOoa5UXr2ujEEPExQcBVXrHpHZpWhGzCAVtZlkAGtf2JcHlDixR1xYWEYTVoUyBRcV0vm/8wVG/LTdwgk5R55x/g+YcfZ5vxSqHhH3Bj8FBaV1+QRJbHhgfbFXdKylRlrjy92GIVly+GqmK6Oq8I9HBXJooRps0RORIsub6Kein5sFj38bOXIN49vfslJcQsUOBV29s/ESco6FSa/Tm86L+kC13z9XwUIy0taE3EQ3zUkkBTDMEGlkbf2PqEMdKgoGg9EzVM2DxzhiGq+qBON0BZRKBfEDy4VWlVE/g2yKWMtYL2+uzVih4dc2kJYsQwP9rzMTBRUJwY2XL3B6b03nz+r0B4esQqbTLr9JyhfhmclKLxdOBXGF9xeCqofVaLvys08NMcSku05xA2yhbm0q36rjS6FZBW7LTt17rheBxpppwcDSOMyqds96jZ+gy88EXTBel085BXuPrugPWyzyGIYwhlsmpCXL+DMpfrXiDM7UY/wPK1cSBUuSuJcoTE8Su8cZ0kqdFYWFeeebX7x7tbDw8Xvy9KocBZeG0+t1e0UqVs/6se6xyjPU2OP3PA5yhzXaWW104wcmBQaWwlQzm+eDwr4o1AOx7Ntbn67MWaxPUECBE5+thO4EBcQxVFLuWRaAlaLFKHFuoj2tHjX3oJno9DTAPY/N8e1MBeOMvPSnq2Mf7bGcKm6giGZ3op9/7BMckPSAxnHYSUpZBeFnsRfSqsSM

06-27 13:08:23.533 D/SMACK: SENT (0):

06-27 13:08:25.033 D/SMACK: RECV (0):

06-27 13:08:25.033 D/SMACK: SENT (0):

06-27 13:08:28.113 E/αTalk: [5] org.jivesoftware.smackx.omemo.OmemoManager.authenticated() connectionListener.authenticated() failed to initialize OmemoManager: No response received within reply timeout. Timeout was 5000ms (~5s). Waited for response using: IQReplyFilter: iqAndIdFilter (AndFilter: (OrFilter: (IQTypeFilter: type=error, IQTypeFilter: type=result), StanzaIdFilter:** id=J8c7V-110**)), : fromFilter (OrFilter: (FromMatchesFilter (full): leopard@atalk.org, FromMatchesFilter (full): null)).

06-27 13:08:28.123 D/SMACK: XMPPConnection authenticated (XMPPTCPConnection[leopard@atalk.org/atalk] (0))

06-27 13:08:29.413 D/SMACK: RECV (0): <iq xml:lang=‘en’ to=‘leopard@atalk.org/atalk’ from=‘leopard@atalk.org’ type=‘result’ id=‘J8c7V-110’>

Hm, I have the same issue on some servers. See Cannot fetch bundles from ejabberd · Issue #25 · vanitasvitae/smack-omemo · GitHub . I ended up assuming it was a configuration failure on server side. Interesting, that you encounter the same issue. I guess I’ll have to dig deeper into that once more.

Hello cmeng could you please post your message sending and receiving code snippet for one to one communication i have setted up all done but it fails to send message using smack 4.2.0

please find my code below

                SignalOmemoService.acknowledgeLicense();
				SignalOmemoService.setup();

				System.out.println("path ");
				String path = sc.nextLine();

				OmemoConfiguration.setFileBasedOmemoStoreDefaultPath(new File("F:\\"));
				omemoManager = OmemoManager.getInstanceFor(connection);
				omemoManager.addOmemoMessageListener(new OmemoMessageListener() {

					@Override
					public void onOmemoKeyTransportReceived(CipherAndAuthTag arg0, Message arg1, Message arg2,
							OmemoMessageInformation arg3) {
						System.out.println("received something ");

					}

					@Override
					public void onOmemoMessageReceived(String arg0, Message arg1, Message arg2,
							OmemoMessageInformation arg3) {
						System.out.println("decrypted message :- " + arg0);

					}
				});

				omemoManager.initialize();

for sending message

                    String to = sc.nextLine();
					Message encrypted;
					String message = sc.nextLine();
					EntityBareJid recipientJid = JidCreate.entityBareFrom(to + "@" + GetXmppConnetion.strServer);
					encrypted = omemoManager.encrypt(recipientJid, message);

i got iq from server like

please help.

Thanks

Hi,

Attached is the full source implementation for omemo support in aTalk-android. Note the implementation uses SQLite backend database.

For File based support, see CryptoActivator# setupOmemoConfigStore() for the required changes.

Below is the snippet for actual sending and receiving of the omemo messages.

Also you may want to review all the discussion threads I have with the igniterealtime development team on omemo.

https://discourse.igniterealtime.org/

The discussion thread hopefully will give you some insight on some limitations posed by current omemo release that you need to take care of in order for omemo to working satisfactory when using smack-4.2.2-SNAPSHOT library.


public void sendInstantMessage(Contact to, ContactResource toResource, Message message,
      OmemoManager omemoManager)
      throws IllegalStateException, IllegalArgumentException
{
   Jid toJid = to.getJid();
   String msgContent = message.getContent();
   org.jivesoftware.smack.packet.Message encryptedMessage = null;
   try {
      encryptedMessage = omemoManager.encrypt(toJid.asBareJid(), msgContent);
      mChat = obtainChatInstance((EntityJid) toJid);
      mChat.sendMessage(encryptedMessage);
   }
   catch (UndecidedOmemoIdentityException e) {
      // logger.warn("There are unTrusted Omemo device: " + e.getMessage());
      HashSet<OmemoDevice> omemoDevices = e.getUndecidedDevices();
      aTalkApp.getGlobalContext().startActivity(
            OmemoAuthenticateDialog.createIntent(omemoManager, omemoDevices, null));
   }
   catch (CannotEstablishOmemoSessionException e) {
      // encryptedMessage = omemoManager.encryptForExistingSessions(e, msgContent);
      logger.warn("Omemo is unable to create session with a device: " + e.getMessage());
   }
   catch (CryptoFailedException | NoSuchAlgorithmException | InterruptedException
         | NotConnectedException | NoResponseException e) {
      e.printStackTrace();
   }
   MessageDeliveredEvent msgDelivered = new MessageDeliveredEvent(message, to);
   fireMessageEvent(msgDelivered);
}

	// =============== OMEMO message received =============== //

	public void registerOmemoListener(OmemoManager omemoManager)
	{
		omemoManager.addOmemoMessageListener(this);
	}

	public void unRegisterOmemoListener(OmemoManager omemoManager)
	{
		omemoManager.removeOmemoMessageListener(this);
	}

	/**
	 * Gets called, whenever an OmemoMessage has been received and was successfully decrypted.
	 *
	 * @param decryptedBody
	 * 		Decrypted body
	 * @param encryptedMessage
	 * 		Encrypted Message
	 * @param wrappingMessage
	 * 		Wrapping carbon message, in case the message was a carbon copy, else null.
	 * @param omemoInformation
	 * 		Information about the messages encryption etc.
	 */
	@Override
	public void onOmemoMessageReceived(String decryptedBody,
			org.jivesoftware.smack.packet.Message encryptedMessage,
			org.jivesoftware.smack.packet.Message wrappingMessage,
			OmemoMessageInformation omemoInformation)
	{
		Jid fromJid = encryptedMessage.getFrom();
		putJidForAddress(fromJid, encryptedMessage.getThread());
		Contact sourceContact = opSetPersPresence.findContactByID(fromJid.toString());
		Date timeStamp = getTimeStamp(encryptedMessage);

		String msgID = encryptedMessage.getStanzaId();
		String correctedMsgID = getCorrectionMessageId(encryptedMessage);

		Message newMessage = createMessageWithUID(decryptedBody, ChatMessage.ENCODE_PLAIN, msgID);
		MessageReceivedEvent msgReceivedEvt =
				new MessageReceivedEvent(newMessage, sourceContact, timeStamp, correctedMsgID);
		fireMessageEvent(msgReceivedEvt);
	}

	/**
	 * Gets called, whenever an OmemoElement without a body (an OmemoKeyTransportElement) is
	 * received.
	 *
	 * @param cipherAndAuthTag
	 * 		transported Cipher along with an optional AuthTag
	 * @param message
	 * 		Message that contained the KeyTransport
	 * @param wrappingMessage
	 * 		Wrapping message (eg. carbon), or null
	 * @param omemoInformation
	 * 		Information about the messages encryption etc.
	 */
	@Override
	public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag,
			org.jivesoftware.smack.packet.Message message,
			org.jivesoftware.smack.packet.Message wrappingMessage,
			OmemoMessageInformation omemoInformation)
	{
	}

crypto.zip (35.8 KB)

Hi Paul, can you provide a use case or an integration guide for integrating OMEMO with MUC?. Do we needto add all group members to the roster?

Hi @Gurupriyan_K_S

Yes, all members of the MUC must subscribe to one another and the MUC itself must be non-anonymous.
Basically smack-omemo then just encrypts messages for each member of the MUC the same way, direct messages are encrypted.
You can use encrypt(MultiUserChat muc, String message) to encrypt messages for a MUC, and addOmemoMucMessageListener(OmemoMucMessageListener listener) to listen for encrypted MUC messages. Thats basically it :slight_smile:

Well, Thanks Paul :wink:

1 Like

No problem. Don’t hesitate to ask :slight_smile:

1 Like

Hi Paul, I’m building a chat app using ejabberd saas, and I’m using MUC/Sub architecture for group messaging( plz refer link https://docs.ejabberd.im/developer/xmpp-clients-bots/proposed-extensions/muc-sub/). As per MUC/Sub use case group members won’t keep their presence in the group, they just join send message and leave but they continue to receive message through PubSub node, so my question is how do we implement OMEMO in this scenario?. I’ve been trying to integrate OMEMO on muc and keep getting this exception:

E/AbstractXMPPConnection: Exception in async packet listener
                                                                                   java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
                                                                                       at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:746)
                                                                                       at org.jivesoftware.smackx.muc.MultiUserChat.getOccupantPresence(MultiUserChat.java:1667)
                                                                                       at org.jivesoftware.smackx.muc.MultiUserChat.getOccupant(MultiUserChat.java:1680)
                                                                                       at org.jivesoftware.smackx.omemo.OmemoService.getSender(OmemoService.java:1184)
                                                                                       at org.jivesoftware.smackx.omemo.OmemoService.access$000(OmemoService.java:106)
                                                                                       at org.jivesoftware.smackx.omemo.OmemoService$OmemoStanzaListener.processStanza(OmemoService.java:1229)
                                                                                       at org.jivesoftware.smack.AbstractXMPPConnection$4.run(AbstractXMPPConnection.java:1198)
                                                                                       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                                                                                       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                                                                                       at java.lang.Thread.run(Thread.java:818)

Send message -

<message to="group_vc61_1513165735179@conference.version.m.in-app.io" id="Z5JzZ-468" type="groupchat">
   <body>I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo</body>
   <encrypted xmlns="eu.siacs.conversations.axolotl">
      <header sid="2013423324">
         <key rid="1104461328">MwohBXEF8d2lz0SBXHUo9kknwKs8DfSwgs4bMZnbxHOKlIUiEAIYACIwCruRRib3mLbm2lZf6/ZxgkSV1lRUClSDtTHjk0cuwCR7MjMhqNfInswXR9krf1THWqReCGXB9JE=</key>
         <iv>PAQrfbUEjoONFWHADFI+QA==</iv>
      </header>
      <payload>UaJfMg==</payload>
   </encrypted>
   <store xmlns="urn:xmpp:hints" />
   <encryption xmlns="urn:xmpp:eme:0" namespace="eu.siacs.conversations.axolotl" name="OMEMO" />
</message>

Received Message -

<message from="group_vc61_1513165735179@conference.version.m.in-app.io/vc61" to="vc61@version.m.in-app.io/vc61" xml:lang="en" id="Z5JzZ-468" type="groupchat">
   <archived xmlns="urn:xmpp:mam:tmp" by="version.m.in-app.io" id="1513169999133292" />
   <stanza-id xmlns="urn:xmpp:sid:0" by="version.m.in-app.io" id="1513169999133292" />
   <body>I sent you an OMEMO encrypted message but your client doesn’t seem to support that. Find more information on https://conversations.im/omemo</body>
   <encrypted xmlns="eu.siacs.conversations.axolotl">
      <header sid="2013423324">
         <key rid="1104461328">MwohBXEF8d2lz0SBXHUo9kknwKs8DfSwgs4bMZnbxHOKlIUiEAIYACIwCruRRib3mLbm2lZf6/ZxgkSV1lRUClSDtTHjk0cuwCR7MjMhqNfInswXR9krf1THWqReCGXB9JE=</key>
         <iv>PAQrfbUEjoONFWHADFI+QA==</iv>
      </header>
      <payload>UaJfMg==</payload>
   </encrypted>
   <store xmlns="urn:xmpp:hints" />
   <encryption xmlns="urn:xmpp:eme:0" namespace="eu.siacs.conversations.axolotl" name="OMEMO" />
</message>

Could you please look into this and support me.
~Thanks :slight_smile: