Smack-omemo rework #177 - throws Exception (key.length == 0) from OmemoManager#encrypt() when buddy is offline

aTalk has a small routine (see below) to check for any UndecidedOmemoIdentity on the initial setup of omemo messaging with a buddy. The exact same routine works ok in previous omemo library release. However when use with reowrk #177, it throws the Exception (key.length == 0) , as shown in the log below. All subsequent omemo messaging sending also failed with the same Exception.

However if the buddy goes offline only after the initial UndecidedOmemoIdentity() check process has completed, then subsequent omemo messaging sending is OK. When the offline buddy again comes online, any offline omemo messages sent early are received, decrypted and displayed correctly on buddy chat window.

========= aTalk routine to check for UndecidedOmemoIdentity ======
                try {
                    mOmemoManager.encrypt(bareJid, "Hi buddy!");
                } catch (UndecidedOmemoIdentityException e) {
                    HashSet<OmemoDevice> omemoDevices = e.getUndecidedDevices();
                    logger.warn("There are undecided Omemo devices: " + omemoDevices);
                    startActivity(OmemoAuthenticateDialog.createIntent(mOmemoManager, omemoDevices, this));
                    allTrusted = false;
                } catch (InterruptedException | SmackException.NoResponseException
                        | CryptoFailedException | SmackException.NotConnectedException e) {
                    mChatType = ChatFragment.MSGTYPE_MUC_NORMAL;
                    activeChat.addMessage(mEntity, new Date(), Chat.ERROR_MESSAGE,
                            getString(R.string.crypto_msg_OMEMO_SESSION_SETUP_FAILED), ChatMessage.ENCODE_PLAIN);
                    logger.info("OMEMO changes mChatType to: " + mChatType);
                    return;
                } catch (SmackException.NotLoggedInException e) {
                    e.printStackTrace();
                }
                catch (Exception ex) { // catch any non-advertised exception
                    logger.warn("UndecidedOmemoIdentity check failed: " + ex.getMessage());
                }

============ aTalk log with Exception (key.length == 0) ===============

01-24 09:44:11.654 E/MessageQueue-JNI: java.lang.IllegalArgumentException: key.length == 0
                                           at javax.crypto.spec.SecretKeySpec.<init>(SecretKeySpec.java:62)
                                           at org.whispersystems.libsignal.ratchet.ChainKey.getBaseMaterial(ChainKey.java:57)
                                           at org.whispersystems.libsignal.ratchet.ChainKey.getMessageKeys(ChainKey.java:47)
                                           at org.whispersystems.libsignal.SessionCipher.encrypt(SessionCipher.java:97)
                                           at org.jivesoftware.smackx.omemo.signal.SignalOmemoRatchet.doubleRatchetEncrypt(SignalOmemoRatchet.java:147)
                                           at org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder.addRecipient(OmemoMessageBuilder.java:239)
                                           at org.jivesoftware.smackx.omemo.OmemoService.encrypt(OmemoService.java:404)
                                           at org.jivesoftware.smackx.omemo.OmemoService.createOmemoMessage(OmemoService.java:523)
                                           at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:337)
                                           at org.jivesoftware.smackx.omemo.OmemoManager.encrypt(OmemoManager.java:309)
                                           at org.atalk.crypto.CryptoFragment.doHandleOmemoPressed(CryptoFragment.java:325)
                                           at org.atalk.crypto.CryptoFragment.onOptionsItemSelected(CryptoFragment.java:236)
                                           at android.support.v4.app.Fragment.performOptionsItemSelected(Fragment.java:2394)
                                           at android.support.v4.app.FragmentManagerImpl.dispatchOptionsItemSelected(FragmentManager.java:3326)
                                           at android.support.v4.app.FragmentController.dispatchOptionsItemSelected(FragmentController.java:344)
                                           at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:386)
                                           at com.android.internal.policy.impl.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1199)
                                           at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:761)
                                           at com.android.internal.view.menu.SubMenuBuilder.dispatchMenuItemSelected(SubMenuBuilder.java:81)
                                           at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:155)
                                           at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:904)
                                           at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:894)
                                           at com.android.internal.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:216)
                                           at android.widget.AdapterView.performItemClick(AdapterView.java:334)
                                           at android.widget.AbsListView.performItemClick(AbsListView.java:1531)
                                           at android.widget.AbsListView$PerformClick.run(AbsListView.java:3664)
                                           at android.widget.AbsListView.onTouchUp(AbsListView.java:5600)
                                           at android.widget.AbsListView.onTouchEvent(AbsListView.java:5366)
                                           at android.view.View.dispatchTouchEvent(View.java:8962)
                                           at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2698)
                                           at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2410)
                                           at android.widget.AbsListView.dispatchTouchEvent(AbsListView.java:5303)
                                           at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2709)
                                           at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2425)
                                           at android.widget.PopupWindow$PopupViewContainer.dispatchTouchEvent(PopupWindow.java:1933)
                                           at android.view.View.dispatchPointerEvent(View.java:9167)
                                           at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4706)
                                           at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4544)
                                           at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
                                           at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4121)
                                           at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4087)
                                           at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4201)
                                           at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4095)
                                           at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4258)
                                           at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
                                           at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4121)
                                           at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4087)
                                           at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4095)
                                           at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
                                           at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6564)

The above problem was observed with consistently failing on repeated tests before issue was open.

For unknown reason after repeated testings, I am unable to reproduce the above problem. It continue to work even I completely re-create a complete new omemo tables for the problem device!!!

Appreciate if somebody can shake some light what can be the possible causes that may lead to the problem observed initially?

I can imagine this is also caused by your SQLiteOmemoStore. Please make sure that loadOmemoIdentityKey(omemoDevice) returns null if the key is not in the db. Thr exception you get is normally thrown when you try to deserialize an identityKey from empty data.