From 50f8a4f1fefd2ef4de3b714738b6835cde1bed11 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 5 Jan 2018 14:49:15 +0100 Subject: [PATCH] Reimplement encryption, solve compiler errors --- .../AbstractTwoUsersOmemoIntegrationTest.java | 2 +- .../MessageEncryptionIntegrationTest.java | 36 +-- .../smackx/omemo/OmemoManagerSetupHelper.java | 10 +- .../SessionRenegotiationIntegrationTest.java | 60 ++--- .../omemo/signal/SignalOmemoService.java | 23 +- .../signal/SignalOmemoStoreConnector.java | 13 +- .../smackx/omemo/SignalOmemoKeyUtilTest.java | 3 +- .../smackx/omemo/SignalOmemoManagerTest.java | 19 +- .../smackx/omemo/OmemoManager.java | 175 ++++++++++---- .../smackx/omemo/OmemoMessage.java | 27 ++- .../smackx/omemo/OmemoRatchet.java | 43 +++- .../smackx/omemo/OmemoService.java | 223 +++++++++++++++--- .../omemo/element/OmemoElement_VAxolotl.java | 4 +- .../smackx/omemo/element/OmemoKeyElement.java | 16 ++ .../UntrustedOmemoIdentityException.java | 12 + .../omemo/internal/CipherAndAuthTag.java | 9 +- .../omemo/listener/OmemoMessageListener.java | 22 +- .../listener/OmemoMucMessageListener.java | 29 +-- .../smackx/omemo/OmemoConfigurationTest.java | 2 - .../smackx/omemo/WrapperObjectsTest.java | 3 +- 20 files changed, 497 insertions(+), 234 deletions(-) diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java index a0c9c8bef..170d0f0db 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/AbstractTwoUsersOmemoIntegrationTest.java @@ -64,7 +64,7 @@ public abstract class AbstractTwoUsersOmemoIntegrationTest extends AbstractOmemo } @AfterClass - public void cleanUp() throws SmackException.NotLoggedInException { + public void cleanUp() { alice.stopListeners(); bob.stopListeners(); OmemoManagerSetupHelper.cleanUpPubSub(alice); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/MessageEncryptionIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/MessageEncryptionIntegrationTest.java index f007aae63..5adab7817 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/MessageEncryptionIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/MessageEncryptionIntegrationTest.java @@ -22,9 +22,8 @@ import static org.junit.Assert.assertFalse; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement; -import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag; -import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation; import org.jivesoftware.smackx.omemo.listener.OmemoMessageListener; import org.igniterealtime.smack.inttest.SmackIntegrationTest; @@ -51,13 +50,13 @@ public class MessageEncryptionIntegrationTest extends AbstractTwoUsersOmemoInteg OmemoBundleElement bobsBundle1 = bob.getOmemoService().getOmemoStoreBackend().packOmemoBundle(bob.getOwnDevice()); final String message1 = "One is greater than zero (for small values of zero)."; - Message encrypted1 = alice.encrypt(bob.getOwnJid(), message1); + OmemoMessage.Sent encrypted1 = alice.encrypt(bob.getOwnJid(), message1); final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint(); bob.addOmemoMessageListener(new OmemoMessageListener() { @Override - public void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - if (decryptedBody.equals(message1)) { + public void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received received) { + if (received.getMessage().equals(message1)) { bobReceivedMessage.signal(); } else { bobReceivedMessage.signalFailure("Received decrypted message was not equal to sent message."); @@ -65,13 +64,16 @@ public class MessageEncryptionIntegrationTest extends AbstractTwoUsersOmemoInteg } @Override - public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - // Not used + public void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage) { + // Not needed } + }); - encrypted1.setTo(bob.getOwnJid()); - alice.getConnection().sendStanza(encrypted1); + Message m1 = new Message(); + m1.addExtension(encrypted1.getElement()); + m1.setTo(bob.getOwnJid()); + alice.getConnection().sendStanza(m1); bobReceivedMessage.waitForResult(10 * 1000); OmemoBundleElement aliceBundle2 = alice.getOmemoService().getOmemoStoreBackend().packOmemoBundle(alice.getOwnDevice()); @@ -82,13 +84,13 @@ public class MessageEncryptionIntegrationTest extends AbstractTwoUsersOmemoInteg assertFalse(bobsBundle1.equals(bobsBundle2)); final String message2 = "The german words for 'leek' and 'wimp' are the same."; - final Message encrypted2 = bob.encrypt(alice.getOwnJid(), message2); + final OmemoMessage.Sent encrypted2 = bob.encrypt(alice.getOwnJid(), message2); final SimpleResultSyncPoint aliceReceivedMessage = new SimpleResultSyncPoint(); alice.addOmemoMessageListener(new OmemoMessageListener() { @Override - public void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - if (decryptedBody.equals(message2)) { + public void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received received) { + if (received.getMessage().equals(message2)) { aliceReceivedMessage.signal(); } else { aliceReceivedMessage.signalFailure("Received decrypted message was not equal to sent message."); @@ -96,13 +98,15 @@ public class MessageEncryptionIntegrationTest extends AbstractTwoUsersOmemoInteg } @Override - public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - // Not needed here either. + public void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage) { + // Not needed } }); - encrypted2.setTo(alice.getOwnJid()); - bob.getConnection().sendStanza(encrypted2); + Message m2 = new Message(); + m2.addExtension(encrypted2.getElement()); + m2.setTo(alice.getOwnJid()); + bob.getConnection().sendStanza(m2); aliceReceivedMessage.waitForResult(10 * 1000); OmemoBundleElement aliceBundle3 = alice.getOmemoService().getOmemoStoreBackend().packOmemoBundle(alice.getOwnDevice()); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java index da0368c89..80a644a3d 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/OmemoManagerSetupHelper.java @@ -25,7 +25,6 @@ import java.util.HashMap; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smackx.omemo.util.EphemeralTrustCallback; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.roster.PresenceEventListener; import org.jivesoftware.smack.roster.Roster; @@ -35,6 +34,7 @@ import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.internal.OmemoCachedDeviceList; import org.jivesoftware.smackx.omemo.internal.OmemoDevice; import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; +import org.jivesoftware.smackx.omemo.util.EphemeralTrustCallback; import org.jivesoftware.smackx.omemo.util.OmemoConstants; import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.PubSubManager; @@ -45,6 +45,7 @@ import org.jxmpp.jid.BareJid; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; + public class OmemoManagerSetupHelper { /** @@ -177,14 +178,11 @@ public class OmemoManagerSetupHelper { } } - public static void cleanUpPubSub(OmemoManager omemoManager) - throws SmackException.NotLoggedInException, XMPPException.XMPPErrorException, - PubSubException.NotALeafNodeException - { + public static void cleanUpPubSub(OmemoManager omemoManager) { PubSubManager pm = PubSubManager.getInstance(omemoManager.getConnection(),omemoManager.getOwnJid()); try { omemoManager.requestDeviceListUpdateFor(omemoManager.getOwnJid()); - } catch (SmackException.NotConnectedException | InterruptedException | SmackException.NoResponseException e) { + } catch (SmackException.NotConnectedException | InterruptedException | SmackException.NoResponseException | PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException e) { // ignore } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/SessionRenegotiationIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/SessionRenegotiationIntegrationTest.java index a9608b7df..fac791572 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/SessionRenegotiationIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/omemo/SessionRenegotiationIntegrationTest.java @@ -23,8 +23,7 @@ import java.util.concurrent.TimeoutException; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; -import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag; -import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.omemo.listener.OmemoMessageListener; import org.igniterealtime.smack.inttest.SmackIntegrationTest; @@ -41,16 +40,16 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn super(environment); } - private static final String m1 = "P = NP is true for all N,P from the set of complex numbers, where P is equal to 0"; + private static final String body1 = "P = NP is true for all N,P from the set of complex numbers, where P is equal to 0"; private final SimpleResultSyncPoint bsp1 = new SimpleResultSyncPoint(); - private final OmemoMessageListener bml1 = new OmemoTestMessageListener(m1, bsp1); + private final OmemoMessageListener bml1 = new OmemoTestMessageListener(body1, bsp1); - private static final String m2 = "P = NP is also true for all N,P from the set of complex numbers, where N is equal to 1."; + private static final String body2 = "P = NP is also true for all N,P from the set of complex numbers, where N is equal to 1."; private final ResultSyncPoint bsp2 = new ResultSyncPoint<>(); private final OmemoMessageListener bml2 = new OmemoMessageListener() { @Override - public void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - if (decryptedBody.equals(m2)) { + public void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received received) { + if (received.getMessage().equals(body2)) { bsp2.signal(new IllegalStateException("Message MUST NOT be decryptable!")); } else { bsp2.signal(new IllegalStateException("OmemoMessageListener MUST NOT be called for this message.")); @@ -58,37 +57,40 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn } @Override - public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - + public void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage) { + // Not needed } }; private final SimpleResultSyncPoint asp2 = new SimpleResultSyncPoint(); private final OmemoMessageListener aml2 = new OmemoMessageListener() { - @Override - public void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation) { + @Override + public void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received decryptedMessage) { + // Not needed } @Override - public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation) { + public void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received received) { asp2.signal(); } }; - private static final String m3 = "P = NP would be a disaster for the world of cryptography."; + private static final String body3 = "P = NP would be a disaster for the world of cryptography."; private final SimpleResultSyncPoint bsp3 = new SimpleResultSyncPoint(); - private final OmemoMessageListener bml3 = new OmemoTestMessageListener(m3, bsp3); + private final OmemoMessageListener bml3 = new OmemoTestMessageListener(body3, bsp3); @SmackIntegrationTest public void sessionRenegotiationTest() throws Exception { /* Send (PreKey-)message from Alice to Bob to initiate a session. */ - Message e1 = alice.encrypt(bob.getOwnJid(), m1); - e1.setTo(bob.getOwnJid()); + OmemoMessage.Sent e1 = alice.encrypt(bob.getOwnJid(), body1); + Message m1 = new Message(); + m1.addExtension(e1.getElement()); + m1.setTo(bob.getOwnJid()); bob.addOmemoMessageListener(bml1); - alice.getConnection().sendStanza(e1); + alice.getConnection().sendStanza(m1); bsp1.waitForResult(10 * 1000); bob.removeOmemoMessageListener(bml1); @@ -100,12 +102,14 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn /* Send normal message from Alice to Bob (Alice assumes, that Bob still has a valid session). */ - Message e2 = alice.encrypt(bob.getOwnJid(), m2); - e2.setTo(bob.getOwnJid()); + OmemoMessage.Sent e2 = alice.encrypt(bob.getOwnJid(), body2); + Message m2 = new Message(); + m2.addExtension(e2.getElement()); + m2.setTo(bob.getOwnJid()); bob.addOmemoMessageListener(bml2); alice.addOmemoMessageListener(aml2); - alice.getConnection().sendStanza(e2); + alice.getConnection().sendStanza(m2); /* Wait for the timeout on Bobs side, since message decryption will fail now. @@ -127,11 +131,13 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn Since Bob responded with a PreKeyMessage to repair the broken session, Alice should now be able to send messages which Bob can decrypt successfully again. */ - Message e3 = alice.encrypt(bob.getOwnJid(), m3); - e3.setTo(bob.getOwnJid()); + OmemoMessage.Sent e3 = alice.encrypt(bob.getOwnJid(), body3); + Message m3 = new Message(); + m3.addExtension(e3.getElement()); + m3.setTo(bob.getOwnJid()); bob.addOmemoMessageListener(bml3); - alice.getConnection().sendStanza(e3); + alice.getConnection().sendStanza(m3); bsp3.waitForResult(10 * 1000); bob.removeOmemoMessageListener(bml3); } @@ -147,8 +153,8 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn } @Override - public void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - if (decryptedBody.equals(expectedMessage)) { + public void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received received) { + if (received.getMessage().equals(expectedMessage)) { syncPoint.signal(); } else { syncPoint.signalFailure("Received decrypted message was not equal to sent message."); @@ -156,8 +162,8 @@ public class SessionRenegotiationIntegrationTest extends AbstractTwoUsersOmemoIn } @Override - public void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation) { - // Ignored. + public void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage) { + } } } diff --git a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoService.java b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoService.java index cdbcc4473..67ab3769e 100644 --- a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoService.java +++ b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoService.java @@ -20,19 +20,8 @@ */ package org.jivesoftware.smackx.omemo.signal; -import java.io.UnsupportedEncodingException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.util.logging.Level; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smackx.omemo.OmemoManager; import org.jivesoftware.smackx.omemo.OmemoService; import org.jivesoftware.smackx.omemo.OmemoStore; @@ -73,11 +62,7 @@ public final class SignalOmemoService return new SignalOmemoRatchet(manager, getOmemoStoreBackend()); } - public static void setup() - throws InvalidKeyException, XMPPErrorException, NoSuchPaddingException, InvalidAlgorithmParameterException, - UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, - NoSuchProviderException, SmackException, InterruptedException, CorruptedOmemoKeyException - { + public static void setup() { if (!LICENSE_ACKNOWLEDGED) { throw new IllegalStateException("smack-omemo-signal is licensed under the terms of the GPLv3. " + "Please be aware that you can only use this library within the terms of the GPLv3. " + @@ -98,11 +83,7 @@ public final class SignalOmemoService return new SignalCachingOmemoStore(); } - private SignalOmemoService() - throws SmackException, InterruptedException, XMPPException.XMPPErrorException, CorruptedOmemoKeyException, - NoSuchPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException, - IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchProviderException, - java.security.InvalidKeyException { + private SignalOmemoService() { super(); } diff --git a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java index ea078dae2..1a7772e08 100644 --- a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java +++ b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoStoreConnector.java @@ -225,18 +225,19 @@ public class SignalOmemoStoreConnector @Override public SignedPreKeyRecord loadSignedPreKey(int i) throws InvalidKeyIdException { - return omemoStore.loadOmemoSignedPreKey(getOurDevice(), i); + SignedPreKeyRecord signedPreKeyRecord = omemoStore.loadOmemoSignedPreKey(getOurDevice(), i); + if (signedPreKeyRecord == null) { + throw new InvalidKeyIdException("No signed preKey with id " + i + " found."); + } + return signedPreKeyRecord; } @Override public List loadSignedPreKeys() { - List signedPreKeyRecordList = new ArrayList<>(); TreeMap signedPreKeyRecordHashMap = omemoStore.loadOmemoSignedPreKeys(getOurDevice()); - signedPreKeyRecordList.addAll(signedPreKeyRecordHashMap.values()); - - return signedPreKeyRecordList; + return new ArrayList<>(signedPreKeyRecordHashMap.values()); } @Override @@ -259,7 +260,7 @@ public class SignalOmemoStoreConnector omemoStore.removeOmemoSignedPreKey(getOurDevice(), i); } - public static OmemoDevice asOmemoDevice(SignalProtocolAddress address) throws XmppStringprepException { + private static OmemoDevice asOmemoDevice(SignalProtocolAddress address) throws XmppStringprepException { return new OmemoDevice(JidCreate.bareFrom(address.getName()), address.getDeviceId()); } diff --git a/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoKeyUtilTest.java b/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoKeyUtilTest.java index c9766ccdc..d14e08ef5 100644 --- a/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoKeyUtilTest.java +++ b/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoKeyUtilTest.java @@ -20,7 +20,6 @@ */ package org.jivesoftware.smackx.omemo; -import java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -51,7 +50,7 @@ public class SignalOmemoKeyUtilTest } @Parameterized.Parameters - public static Collection getParameters() throws IOException { + public static Collection getParameters() { return Arrays.asList(new Object[][] { { new SignalOmemoKeyUtil()} }); diff --git a/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoManagerTest.java b/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoManagerTest.java index 64fd6ae0d..64d07a9ff 100644 --- a/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoManagerTest.java +++ b/smack-omemo-signal/src/test/java/org/jivesoftware/smackx/omemo/SignalOmemoManagerTest.java @@ -26,23 +26,11 @@ import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertNotSame; import static junit.framework.TestCase.assertTrue; -import java.io.UnsupportedEncodingException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - import org.jivesoftware.smack.DummyConnection; -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smackx.omemo.element.OmemoElement; -import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider; import org.jivesoftware.smackx.omemo.signal.SignalOmemoService; @@ -54,12 +42,7 @@ import org.junit.Test; public class SignalOmemoManagerTest extends SmackTestSuite { @Test - public void instantiationTest() - throws CorruptedOmemoKeyException, NoSuchAlgorithmException, UnsupportedEncodingException, - InvalidKeyException, InterruptedException, XMPPException.XMPPErrorException, NoSuchPaddingException, - BadPaddingException, InvalidAlgorithmParameterException, NoSuchProviderException, IllegalBlockSizeException, - SmackException - { + public void instantiationTest() { SignalOmemoService.acknowledgeLicense(); SignalOmemoService.setup(); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoManager.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoManager.java index 62cb8f356..e6fd46d43 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoManager.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoManager.java @@ -29,6 +29,7 @@ import java.util.Random; import java.util.SortedSet; import java.util.TreeMap; import java.util.WeakHashMap; +import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.AbstractConnectionListener; @@ -38,6 +39,7 @@ import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.StanzaFilter; +import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.packet.Stanza; @@ -52,22 +54,26 @@ import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.smackx.muc.MultiUserChatManager; import org.jivesoftware.smackx.muc.RoomInfo; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement; +import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement; +import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl; import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.NoOmemoSupportException; import org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException; -import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag; import org.jivesoftware.smackx.omemo.internal.OmemoCachedDeviceList; import org.jivesoftware.smackx.omemo.internal.OmemoDevice; -import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation; import org.jivesoftware.smackx.omemo.listener.OmemoMessageListener; import org.jivesoftware.smackx.omemo.listener.OmemoMucMessageListener; import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; import org.jivesoftware.smackx.omemo.trust.TrustCallback; import org.jivesoftware.smackx.omemo.trust.TrustState; +import org.jivesoftware.smackx.pep.PEPListener; import org.jivesoftware.smackx.pep.PEPManager; +import org.jivesoftware.smackx.pubsub.EventElement; +import org.jivesoftware.smackx.pubsub.ItemsExtension; +import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.packet.PubSub; @@ -245,7 +251,7 @@ public final class OmemoManager extends Manager { * * @param finishedCallback callback that gets called once the manager is initialized. */ - public void initializeAsync(final FinishedCallback finishedCallback) { + public void initializeAsync(final InitializationFinishedCallback finishedCallback) { Async.go(new Runnable() { @Override public void run() { @@ -287,8 +293,8 @@ public final class OmemoManager extends Manager { * @throws SmackException.NoResponseException */ public OmemoMessage.Sent encrypt(BareJid recipient, String message) - throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, - InterruptedException, CannotEstablishOmemoSessionException, SmackException.NotConnectedException, + throws CryptoFailedException, UndecidedOmemoIdentityException, + InterruptedException, SmackException.NotConnectedException, SmackException.NoResponseException, SmackException.NotLoggedInException { synchronized (LOCK) { @@ -314,8 +320,8 @@ public final class OmemoManager extends Manager { * @throws SmackException.NoResponseException */ public OmemoMessage.Sent encrypt(ArrayList recipients, String message) - throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, - InterruptedException, CannotEstablishOmemoSessionException, SmackException.NotConnectedException, + throws CryptoFailedException, UndecidedOmemoIdentityException, + InterruptedException, SmackException.NotConnectedException, SmackException.NoResponseException, SmackException.NotLoggedInException { synchronized (LOCK) { @@ -346,9 +352,9 @@ public final class OmemoManager extends Manager { * with any of their devices. */ public OmemoMessage.Sent encrypt(MultiUserChat muc, String message) - throws UndecidedOmemoIdentityException, NoSuchAlgorithmException, CryptoFailedException, + throws UndecidedOmemoIdentityException, CryptoFailedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, - SmackException.NoResponseException, NoOmemoSupportException, CannotEstablishOmemoSessionException, + SmackException.NoResponseException, NoOmemoSupportException, SmackException.NotLoggedInException { synchronized (LOCK) { @@ -722,6 +728,10 @@ public final class OmemoManager extends Manager { } } + /** + * Set the deviceId of the manager to nDeviceId. + * @param nDeviceId new deviceId + */ void setDeviceId(int nDeviceId) { synchronized (LOCK) { // Move this instance inside the HashMaps @@ -735,64 +745,58 @@ public final class OmemoManager extends Manager { /** * Notify all registered OmemoMessageListeners about a received OmemoMessage. * - * @param decryptedBody decrypted Body element of the message - * @param encryptedMessage unmodified message as it was received - * @param wrappingMessage message that wrapped the incoming message - * @param messageInformation information about the messages encryption (used identityKey, carbon...) + * @param stanza original stanza + * @param decryptedMessage decrypted OmemoMessage. */ - void notifyOmemoMessageReceived(String decryptedBody, - Message encryptedMessage, - Message wrappingMessage, - OmemoMessageInformation messageInformation) + void notifyOmemoMessageReceived(Stanza stanza, OmemoMessage.Received decryptedMessage) { for (OmemoMessageListener l : omemoMessageListeners) { - l.onOmemoMessageReceived(decryptedBody, encryptedMessage, wrappingMessage, messageInformation); + l.onOmemoMessageReceived(stanza, decryptedMessage); } } - void notifyOmemoKeyTransportMessageReceived(CipherAndAuthTag cipherAndAuthTag, - Message transportingMessage, - Message wrappingMessage, - OmemoMessageInformation information) + /** + * Notify all registered OmemoMessageListeners about a received OMEMO KeyTransportMessage. + * + * @param stanza original stanza. + * @param decryptedKeyTransportMessage decrypted KeyTransportMessage. + */ + void notifyOmemoKeyTransportMessageReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage) { for (OmemoMessageListener l : omemoMessageListeners) { - l.onOmemoKeyTransportReceived(cipherAndAuthTag, transportingMessage, wrappingMessage, information); + l.onOmemoKeyTransportReceived(stanza, decryptedKeyTransportMessage); } } /** * Notify all registered OmemoMucMessageListeners of an incoming OmemoMessageElement in a MUC. * - * @param muc MultiUserChat the message was received in - * @param from BareJid of the user that sent the message - * @param decryptedBody decrypted body - * @param message original message with encrypted content - * @param wrappingMessage wrapping message (in case of carbon copy) - * @param omemoInformation information about the encryption of the message + * @param muc MultiUserChat the message was received in. + * @param stanza Original Stanza. + * @param decryptedMessage Decryped OmemoMessage. */ void notifyOmemoMucMessageReceived(MultiUserChat muc, - BareJid from, - String decryptedBody, - Message message, - Message wrappingMessage, - OmemoMessageInformation omemoInformation) + Stanza stanza, + OmemoMessage.Received decryptedMessage) { for (OmemoMucMessageListener l : omemoMucMessageListeners) { - l.onOmemoMucMessageReceived(muc, from, decryptedBody, message, - wrappingMessage, omemoInformation); + l.onOmemoMucMessageReceived(muc, stanza, decryptedMessage); } } + /** + * Notify registered OmemoMucMessageReceived listeners about KeyTransportMessages sent in a MUC. + * + * @param muc MultiUserChat in which the message was sent + * @param stanza original stanza + * @param decryptedKeyTransportMessage decrypted OMEMO KeyTransportElement + */ void notifyOmemoMucKeyTransportMessageReceived(MultiUserChat muc, - BareJid from, - CipherAndAuthTag cipherAndAuthTag, - Message transportingMessage, - Message wrappingMessage, - OmemoMessageInformation messageInformation) + Stanza stanza, + OmemoMessage.Received decryptedKeyTransportMessage) { for (OmemoMucMessageListener l : omemoMucMessageListeners) { - l.onOmemoKeyTransportReceived(muc, from, cipherAndAuthTag, - transportingMessage, wrappingMessage, messageInformation); + l.onOmemoKeyTransportReceived(muc, stanza, decryptedKeyTransportMessage); } } @@ -808,10 +812,10 @@ public final class OmemoManager extends Manager { // Remove listeners to avoid them getting added twice connection().removeAsyncStanzaListener(internalOmemoMessageStanzaListener); carbonManager.removeCarbonCopyReceivedListener(internalOmemoCarbonCopyListener); - //pepManager.removePEPListener(deviceListUpdateListener); + pepManager.removePEPListener(deviceListUpdateListener); // Add listeners - //pepManager.addPEPListener(deviceListUpdateListener); + pepManager.addPEPListener(deviceListUpdateListener); connection().addAsyncStanzaListener(internalOmemoMessageStanzaListener, omemoMessageStanzaFilter); carbonManager.addCarbonCopyReceivedListener(internalOmemoCarbonCopyListener); } @@ -820,7 +824,7 @@ public final class OmemoManager extends Manager { * Remove active stanza listeners needed for OMEMO. */ public void stopListeners() { - //PEPManager.getInstanceFor(connection()).removePEPListener(deviceListUpdateListener); + PEPManager.getInstanceFor(connection()).removePEPListener(deviceListUpdateListener); connection().removeAsyncStanzaListener(internalOmemoMessageStanzaListener); CarbonManager.getInstanceFor(connection()).removeCarbonCopyReceivedListener(internalOmemoCarbonCopyListener); } @@ -844,6 +848,9 @@ public final class OmemoManager extends Manager { return service; } + /** + * StanzaListener that listens for incoming Stanzas which contain OMEMO elements. + */ private final StanzaListener internalOmemoMessageStanzaListener = new StanzaListener() { @Override public void processStanza(Stanza packet) throws SmackException.NotConnectedException, InterruptedException { @@ -856,6 +863,9 @@ public final class OmemoManager extends Manager { } }; + /** + * CarbonCopyListener that listens for incoming carbon copies which contain OMEMO elements. + */ private final CarbonCopyReceivedListener internalOmemoCarbonCopyListener = new CarbonCopyReceivedListener() { @Override public void onCarbonCopyReceived(CarbonExtension.Direction direction, @@ -872,6 +882,64 @@ public final class OmemoManager extends Manager { } }; + /** + * PEPListener that listens for OMEMO deviceList updates. + */ + private final PEPListener deviceListUpdateListener = new PEPListener() { + @Override + public void eventReceived(EntityBareJid from, EventElement event, Message message) { + + // Unknown sender, no more work to do. + if (from == null) { + // TODO: This DOES happen for some reason. Figure out when... + return; + } + + for (ExtensionElement items : event.getExtensions()) { + if (!(items instanceof ItemsExtension)) { + continue; + } + + for (ExtensionElement item : ((ItemsExtension) items).getItems()) { + if (!(item instanceof PayloadItem)) { + continue; + } + + PayloadItem payloadItem = (PayloadItem) item; + + if (!(payloadItem.getPayload() instanceof OmemoDeviceListElement)) { + continue; + } + + // Device List + OmemoDeviceListElement receivedDeviceList = (OmemoDeviceListElement) payloadItem.getPayload(); + getOmemoService().getOmemoStoreBackend().mergeCachedDeviceList(getOwnDevice(), from, receivedDeviceList); + + if (!from.asBareJid().equals(getOwnJid())) { + continue; + } + + OmemoCachedDeviceList deviceList = getOmemoService().cleanUpDeviceList(getOwnDevice()); + final OmemoDeviceListElement_VAxolotl newDeviceList = new OmemoDeviceListElement_VAxolotl(deviceList); + + if (!newDeviceList.equals(receivedDeviceList)) { + Async.go(new Runnable() { + @Override + public void run() { + try { + OmemoService.publishDeviceList(connection(), newDeviceList); + } catch (InterruptedException | XMPPException.XMPPErrorException | + SmackException.NotConnectedException | SmackException.NoResponseException e) { + LOGGER.log(Level.WARNING, "Could not publish our deviceList upon an received update.", e); + } + } + }); + } + } + } + } + }; + /** * StanzaFilter that filters messages containing a OMEMO element. */ @@ -882,6 +950,9 @@ public final class OmemoManager extends Manager { } }; + /** + * Guard class which ensures that the wrapped OmemoManager knows its BareJid. + */ public static class LoggedInOmemoManager { private final OmemoManager manager; @@ -909,13 +980,23 @@ public final class OmemoManager extends Manager { } } - public interface FinishedCallback { + /** + * Callback which can be used to get notified, when the OmemoManager finished initializing. + */ + public interface InitializationFinishedCallback { void initializationFinished(OmemoManager manager); void initializationFailed(Exception cause); } + /** + * Get the bareJid of the user from the authenticated XMPP connection. + * If our deviceId is unknown, use the bareJid to look up deviceIds available in the omemoStore. + * If there are ids available, choose the smallest one. Otherwise generate a random deviceId. + * + * @param manager OmemoManager + */ private static void initBareJidAndDeviceId(OmemoManager manager) { if (!manager.getConnection().isAuthenticated()) { throw new IllegalStateException("Connection MUST be authenticated."); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoMessage.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoMessage.java index 5ba1887b1..5729cfb78 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoMessage.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoMessage.java @@ -34,21 +34,32 @@ import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; public class OmemoMessage { private final OmemoElement element; + private final byte[] messageKey, iv; - OmemoMessage(OmemoElement element) { + OmemoMessage(OmemoElement element, byte[] key, byte[] iv) { this.element = element; + this.messageKey = key; + this.iv = iv; } public OmemoElement getElement() { return element; } + public byte[] getKey() { + return messageKey.clone(); + } + + public byte[] getIv() { + return iv.clone(); + } + public static class Sent extends OmemoMessage { private final ArrayList intendedDevices = new ArrayList<>(); private final HashMap skippedDevices = new HashMap<>(); - Sent(OmemoElement element, List intendedDevices, HashMap skippedDevices) { - super(element); + Sent(OmemoElement element, byte[] key, byte[] iv, List intendedDevices, HashMap skippedDevices) { + super(element, key, iv); this.intendedDevices.addAll(intendedDevices); this.skippedDevices.putAll(skippedDevices); } @@ -86,13 +97,15 @@ public class OmemoMessage { private final OmemoFingerprint sendersFingerprint; private final OmemoDevice senderDevice; private final CARBON carbon; + private final boolean preKeyMessage; - Received(OmemoElement element, String message, OmemoFingerprint sendersFingerprint, OmemoDevice senderDevice, CARBON carbon) { - super(element); + Received(OmemoElement element, byte[] key, byte[] iv, String message, OmemoFingerprint sendersFingerprint, OmemoDevice senderDevice, CARBON carbon, boolean preKeyMessage) { + super(element, key, iv); this.message = message; this.sendersFingerprint = sendersFingerprint; this.senderDevice = senderDevice; this.carbon = carbon; + this.preKeyMessage = preKeyMessage; } public String getMessage() { @@ -115,6 +128,10 @@ public class OmemoMessage { public CARBON getCarbon() { return carbon; } + + boolean isPreKeyMessage() { + return preKeyMessage; + } } /** diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java index f75473771..3d505798c 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java @@ -24,7 +24,6 @@ import java.util.logging.Logger; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; -import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.element.OmemoKeyElement; @@ -43,16 +42,41 @@ public abstract class OmemoRatchet store; + /** + * Constructor. + * + * @param omemoManager omemoManager + * @param store omemoStore + */ public OmemoRatchet(OmemoManager omemoManager, OmemoStore store) { this.omemoManager = omemoManager; this.store = store; } + /** + * Decrypt a double-ratchet-encrypted message key. + * + * @param sender sender of the message. + * @param encryptedKey key encrypted with the ratchet of the sender. + * @return decrypted message key. + * + * @throws CorruptedOmemoKeyException + * @throws NoRawSessionException + * @throws CryptoFailedException + * @throws UntrustedOmemoIdentityException + */ public abstract byte[] doubleRatchetDecrypt(OmemoDevice sender, byte[] encryptedKey) throws CorruptedOmemoKeyException, NoRawSessionException, CryptoFailedException, UntrustedOmemoIdentityException; + /** + * Encrypt a messageKey with the double ratchet session of the recipient. + * + * @param recipient recipient of the message. + * @param messageKey key we want to encrypt. + * @return encrypted message key. + */ public abstract CiphertextTuple doubleRatchetEncrypt(OmemoDevice recipient, byte[] messageKey); /** @@ -70,11 +94,14 @@ public abstract class OmemoRatchet decryptExceptions = new ArrayList<>(); List keys = element.getHeader().getKeys(); + boolean preKey = false; + // Find key with our ID. for (OmemoKeyElement k : keys) { if (k.getId() == keyId) { try { unpackedKey = doubleRatchetDecrypt(sender, k.getData()); + preKey = k.isPreKey(); break; } catch (CryptoFailedException e) { // There might be multiple keys with our id, but we can only decrypt one. @@ -114,7 +141,7 @@ public abstract class OmemoRatchet INSTANCE; - protected OmemoStore omemoStore; - protected final HashMap> omemoRatchets = new HashMap<>(); + private OmemoStore omemoStore; + private final HashMap> omemoRatchets = new HashMap<>(); /** * Create a new OmemoService object. This should only happen once. @@ -120,10 +129,7 @@ public abstract class OmemoService omemoStore) { if (this.omemoStore != null) { @@ -342,11 +349,11 @@ public abstract class OmemoService contactsDevices, - byte[] messageKey, - byte[] iv, - String message) + private OmemoMessage.Sent encrypt(OmemoManager.LoggedInOmemoManager managerGuard, + List contactsDevices, + byte[] messageKey, + byte[] iv, + String message) throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, UndecidedOmemoIdentityException, CryptoFailedException { @@ -418,23 +425,72 @@ public abstract class OmemoServiceXEP-0384: Sending a key. + * + * @param managerGuard Initialized OmemoManager. + * @param contactsDevices recipient devices. + * @param key AES-Key to be transported. + * @param iv initialization vector to be used with the key. + * @return KeyTransportElement * - * @param managerGuard - * @param contactsDevices - * @param key - * @param iv - * @return * @throws InterruptedException * @throws UndecidedOmemoIdentityException if the list of recipients contains an undecided device * @throws CryptoFailedException if we are lacking some cryptographic algorithms * @throws SmackException.NotConnectedException * @throws SmackException.NoResponseException */ - OmemoMessage.Sent createKeyTransportMessage(OmemoManager.LoggedInOmemoManager managerGuard, + OmemoMessage.Sent createKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard, List contactsDevices, byte[] key, byte[] iv) @@ -570,14 +626,24 @@ public abstract class OmemoService(deviceList)); } + /** + * + * @param connection + * @param userDevice + * @throws InterruptedException + * @throws PubSubException.NotALeafNodeException + * @throws XMPPException.XMPPErrorException + * @throws SmackException.NotConnectedException + * @throws SmackException.NoResponseException + */ private void refreshAndRepublishDeviceList(XMPPConnection connection, OmemoDevice userDevice) throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException @@ -592,21 +658,10 @@ public abstract class OmemoServiceemptySet()); } - OmemoCachedDeviceList cachedList = getOmemoStoreBackend().mergeCachedDeviceList( - userDevice, userDevice.getJid(), publishedList); + getOmemoStoreBackend().mergeCachedDeviceList(userDevice, userDevice.getJid(), publishedList); - // Delete stale devices if allowed and necessary - if (OmemoConfiguration.getDeleteStaleDevices()) { - cachedList = deleteStaleDevices(userDevice); - } - - // Add back our device if necessary - if (!cachedList.getActiveDevices().contains(userDevice.getDeviceId())) { - cachedList.addDevice(userDevice.getDeviceId()); - } - - getOmemoStoreBackend().storeCachedDeviceList(userDevice, userDevice.getJid(), cachedList); + OmemoCachedDeviceList cachedList = cleanUpDeviceList(userDevice); // Republish our deviceId if it is missing from the published list. if (!publishedList.getDeviceIds().equals(cachedList.getActiveDevices())) { @@ -614,6 +669,33 @@ public abstract class OmemoService devices) { + private static void removeOurDevice(OmemoDevice userDevice, Collection devices) { if (devices.contains(userDevice)) { devices.remove(userDevice); } @@ -996,7 +1078,74 @@ public abstract class OmemoService joinedRooms = mucm.getJoinedRooms(); + if (joinedRooms.contains(ebj)) { + return mucm.getMultiUserChat(ebj); + } + + return null; } } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java index 49d77ad40..858ac6151 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java @@ -25,6 +25,8 @@ import static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_ */ public class OmemoElement_VAxolotl extends OmemoElement { + public static final String NAMESPACE = OMEMO_NAMESPACE_V_AXOLOTL; + /** * Create a new OmemoMessageElement from a header and a payload. * @@ -37,6 +39,6 @@ public class OmemoElement_VAxolotl extends OmemoElement { @Override public String getNamespace() { - return OMEMO_NAMESPACE_V_AXOLOTL; + return NAMESPACE; } } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java index cb7a4a461..6a9656700 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java @@ -1,3 +1,19 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jivesoftware.smackx.omemo.element; import org.jivesoftware.smack.packet.NamedElement; diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/UntrustedOmemoIdentityException.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/UntrustedOmemoIdentityException.java index 65c128225..6f3ca4c2b 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/UntrustedOmemoIdentityException.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/UntrustedOmemoIdentityException.java @@ -78,4 +78,16 @@ public class UntrustedOmemoIdentityException extends Exception { public OmemoFingerprint getUntrustedFingerprint() { return untrustedKey; } + + @Override + public String toString() { + if (trustedKey != null) { + return "Untrusted OMEMO Identity encountered:\n" + + "Fingerprint of trusted key:\n" + trustedKey.blocksOf8Chars() + "\n" + + "Fingerprint of untrusted key:\n" + untrustedKey.blocksOf8Chars(); + } else { + return "Untrusted OMEMO Identity encountered:\n" + + "Fingerprint of untrusted key:\n" + untrustedKey.blocksOf8Chars(); + } + } } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CipherAndAuthTag.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CipherAndAuthTag.java index 70df61b8c..964a33910 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CipherAndAuthTag.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CipherAndAuthTag.java @@ -23,7 +23,6 @@ import static org.jivesoftware.smackx.omemo.util.OmemoConstants.Crypto.PROVIDER; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; - import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; @@ -38,11 +37,13 @@ import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; */ public class CipherAndAuthTag { private final byte[] key, iv, authTag; + private final boolean wasPreKey; - public CipherAndAuthTag(byte[] key, byte[] iv, byte[] authTag) throws CryptoFailedException { + public CipherAndAuthTag(byte[] key, byte[] iv, byte[] authTag, boolean wasPreKey) { this.authTag = authTag; this.key = key; this.iv = iv; + this.wasPreKey = wasPreKey; } public Cipher getCipher() throws CryptoFailedException { @@ -82,4 +83,8 @@ public class CipherAndAuthTag { } return null; } + + public boolean wasPreKeyEncrypted() { + return wasPreKey; + } } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMessageListener.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMessageListener.java index 9ca870aaf..160208ce7 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMessageListener.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMessageListener.java @@ -16,10 +16,8 @@ */ package org.jivesoftware.smackx.omemo.listener; -import org.jivesoftware.smack.packet.Message; - -import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag; -import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smackx.omemo.OmemoMessage; /** * Listener interface that allows implementations to receive decrypted OMEMO messages. @@ -30,20 +28,16 @@ public interface OmemoMessageListener { /** * 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. + * @param stanza Received (encrypted) stanza. + * @param decryptedMessage decrypted OmemoMessage. */ - void onOmemoMessageReceived(String decryptedBody, Message encryptedMessage, Message wrappingMessage, OmemoMessageInformation omemoInformation); + void onOmemoMessageReceived(Stanza stanza, OmemoMessage.Received decryptedMessage); /** * 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. + * @param stanza received (encrypted) stanza. + * @param decryptedKeyTransportMessage decrypted OMEMO key transport message. */ - void onOmemoKeyTransportReceived(CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation); + void onOmemoKeyTransportReceived(Stanza stanza, OmemoMessage.Received decryptedKeyTransportMessage); } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMucMessageListener.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMucMessageListener.java index 7d0011a8a..78c0fd784 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMucMessageListener.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/listener/OmemoMucMessageListener.java @@ -16,13 +16,9 @@ */ package org.jivesoftware.smackx.omemo.listener; -import org.jivesoftware.smack.packet.Message; - +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.muc.MultiUserChat; -import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag; -import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation; - -import org.jxmpp.jid.BareJid; +import org.jivesoftware.smackx.omemo.OmemoMessage; /** * Listener interface that allows implementations to receive decrypted OMEMO MUC messages. @@ -33,24 +29,17 @@ public interface OmemoMucMessageListener { /** * Gets called whenever an OMEMO message has been received in a MultiUserChat and successfully decrypted. * @param muc MultiUserChat the message was sent in - * @param from the bareJid of the sender - * @param decryptedBody the decrypted Body of the message - * @param message the original message with encrypted element - * @param wrappingMessage in case of a carbon copy, this is the wrapping message - * @param omemoInformation information about the encryption of the message + * @param stanza Original Stanza + * @param decryptedOmemoMessage decrypted Omemo message */ - void onOmemoMucMessageReceived(MultiUserChat muc, BareJid from, String decryptedBody, Message message, - Message wrappingMessage, OmemoMessageInformation omemoInformation); + void onOmemoMucMessageReceived(MultiUserChat muc, Stanza stanza, OmemoMessage.Received decryptedOmemoMessage); /** * Gets called, whenever an OmemoElement without a body (an OmemoKeyTransportElement) is received. * - * @param muc MultiUserChat the message was sent in - * @param from bareJid of the sender - * @param cipherAndAuthTag transportedKey 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. + * @param muc MultiUserChat the message was sent in + * @param stanza original stanza + * @param decryptedKeyTransportElement decrypted KeyTransportMessage */ - void onOmemoKeyTransportReceived(MultiUserChat muc, BareJid from, CipherAndAuthTag cipherAndAuthTag, Message message, Message wrappingMessage, OmemoMessageInformation omemoInformation); + void onOmemoKeyTransportReceived(MultiUserChat muc, Stanza stanza, OmemoMessage.Received decryptedKeyTransportElement); } diff --git a/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/OmemoConfigurationTest.java b/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/OmemoConfigurationTest.java index 48c7755be..765ba6703 100644 --- a/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/OmemoConfigurationTest.java +++ b/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/OmemoConfigurationTest.java @@ -21,8 +21,6 @@ import static org.junit.Assert.assertNull; import java.io.File; -import org.jivesoftware.smackx.omemo.OmemoConfiguration; - import junit.framework.TestCase; import org.junit.Test; diff --git a/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/WrapperObjectsTest.java b/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/WrapperObjectsTest.java index 6b0ff9051..43eb4353c 100644 --- a/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/WrapperObjectsTest.java +++ b/smack-omemo/src/test/java/org/jivesoftware/smackx/omemo/WrapperObjectsTest.java @@ -61,11 +61,12 @@ public class WrapperObjectsTest { byte[] iv = OmemoMessageBuilder.generateIv(); byte[] authTag = OmemoMessageBuilder.generateIv(); - CipherAndAuthTag cat = new CipherAndAuthTag(key, iv, authTag); + CipherAndAuthTag cat = new CipherAndAuthTag(key, iv, authTag, true); assertNotNull(cat.getCipher()); assertArrayEquals(key, cat.getKey()); assertArrayEquals(iv, cat.getIv()); assertArrayEquals(authTag, cat.getAuthTag()); + assertTrue(cat.wasPreKeyEncrypted()); } }