1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-12-06 02:51:11 +01:00

Add OMEMO support

This commit adds the modules smack-omemo and smack-omemo-signal.
smack-omemo is licensed under the Apache license like the rest of the smack project.
smack-omemo-signal on the other hand is licensed under the GPLv3.
Due to the fact, that smack-omemo is not of much use without smack-omemo-signal,
the OMEMO feature can currently only be used by GPLv3 compatible software.
This may change in the future, when a more permissively licensed module becomes available.

Fixes SMACK-743.
This commit is contained in:
vanitasvitae 2017-06-02 12:26:37 +02:00 committed by Florian Schmaus
parent ce36fb468c
commit e86700b040
95 changed files with 11770 additions and 22 deletions

View file

@ -0,0 +1,70 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Test behavior of device lists.
*
* @author Paul Schaub
*/
public class DeviceListTest {
/**
* Test, whether deviceList updates are correctly merged into the cached device list.
* IDs in the update become active devices, active IDs that were not in the update become inactive.
* Inactive IDs that were not in the update stay inactive.
*/
@Test
public void mergeDeviceListsTest() {
CachedDeviceList cached = new CachedDeviceList();
assertNotNull(cached.getActiveDevices());
assertNotNull(cached.getInactiveDevices());
cached.getInactiveDevices().add(1);
cached.getInactiveDevices().add(2);
cached.getActiveDevices().add(3);
Set<Integer> update = new HashSet<>();
update.add(4);
update.add(1);
cached.merge(update);
assertTrue(cached.getActiveDevices().contains(1) &&
!cached.getActiveDevices().contains(2) &&
!cached.getActiveDevices().contains(3) &&
cached.getActiveDevices().contains(4));
assertTrue(!cached.getInactiveDevices().contains(1) &&
cached.getInactiveDevices().contains(2) &&
cached.getInactiveDevices().contains(3) &&
!cached.getInactiveDevices().contains(4));
assertTrue(cached.getAllDevices().size() == 4);
}
}

View file

@ -0,0 +1,96 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement;
import org.jivesoftware.smackx.omemo.provider.OmemoBundleVAxolotlProvider;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test serialization and parsing of the OmemoBundleVAxolotlElement.
*/
public class OmemoBundleVAxolotlElementTest extends SmackTestSuite {
@Test
public void serializationTest() throws Exception {
int signedPreKeyId = 420;
String signedPreKeyB64 = Base64.encodeToString("SignedPreKey".getBytes(StringUtils.UTF8));
String signedPreKeySigB64 = Base64.encodeToString("SignedPreKeySignature".getBytes(StringUtils.UTF8));
String identityKeyB64 = Base64.encodeToString("IdentityKey".getBytes(StringUtils.UTF8));
int preKeyId1 = 220, preKeyId2 = 284;
String preKey1B64 = Base64.encodeToString("FirstPreKey".getBytes(StringUtils.UTF8)),
preKey2B64 = Base64.encodeToString("SecondPreKey".getBytes(StringUtils.UTF8));
HashMap<Integer, String> preKeysB64 = new HashMap<>();
preKeysB64.put(preKeyId1, preKey1B64);
preKeysB64.put(preKeyId2, preKey2B64);
OmemoBundleVAxolotlElement bundle = new OmemoBundleVAxolotlElement(signedPreKeyId,
signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64);
assertEquals("ElementName must match.", "bundle", bundle.getElementName());
assertEquals("Namespace must match.", "eu.siacs.conversations.axolotl", bundle.getNamespace());
String expected =
"<bundle xmlns='eu.siacs.conversations.axolotl'>" +
"<signedPreKeyPublic signedPreKeyId='420'>" +
signedPreKeyB64 +
"</signedPreKeyPublic>" +
"<signedPreKeySignature>" +
signedPreKeySigB64 +
"</signedPreKeySignature>" +
"<identityKey>" +
identityKeyB64 +
"</identityKey>" +
"<prekeys>" +
"<preKeyPublic preKeyId='220'>" +
preKey1B64 +
"</preKeyPublic>" +
"<preKeyPublic preKeyId='284'>" +
preKey2B64 +
"</preKeyPublic>" +
"</prekeys>" +
"</bundle>";
String actual = bundle.toXML().toString();
assertEquals("Bundles XML must match.", expected, actual);
byte[] signedPreKey = "SignedPreKey".getBytes(StringUtils.UTF8);
byte[] signedPreKeySig = "SignedPreKeySignature".getBytes(StringUtils.UTF8);
byte[] identityKey = "IdentityKey".getBytes(StringUtils.UTF8);
byte[] firstPreKey = "FirstPreKey".getBytes(StringUtils.UTF8);
byte[] secondPreKey = "SecondPreKey".getBytes(StringUtils.UTF8);
OmemoBundleVAxolotlElement parsed = new OmemoBundleVAxolotlProvider().parse(TestUtils.getParser(actual));
assertTrue("B64-decoded signedPreKey must match.", Arrays.equals(signedPreKey, parsed.getSignedPreKey()));
assertEquals("SignedPreKeyId must match", signedPreKeyId, parsed.getSignedPreKeyId());
assertTrue("B64-decoded signedPreKey signature must match.", Arrays.equals(signedPreKeySig, parsed.getSignedPreKeySignature()));
assertTrue("B64-decoded identityKey must match.", Arrays.equals(identityKey, parsed.getIdentityKey()));
assertTrue("B64-decoded first preKey must match.", Arrays.equals(firstPreKey, parsed.getPreKey(220)));
assertTrue("B64-decoded second preKey must match.", Arrays.equals(secondPreKey, parsed.getPreKey(284)));
assertEquals("toString outputs must match.", bundle.toString(), parsed.toString());
}
}

View file

@ -0,0 +1,112 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import junit.framework.TestCase;
import org.jivesoftware.smackx.omemo.OmemoConfiguration;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Test the OmemoConfiguration class.
*/
public class OmemoConfigurationTest {
@Test
public void omemoConfigurationTest() {
@SuppressWarnings("unused") OmemoConfiguration configuration = new OmemoConfiguration();
// Default Store Path
File storePath = new File("test");
assertNull("getFileBasedOmemoStoreDefaultPath MUST return null at this point.",
OmemoConfiguration.getFileBasedOmemoStoreDefaultPath());
OmemoConfiguration.setFileBasedOmemoStoreDefaultPath(storePath);
assertEquals("FileBasedOmemoStoreDefaultPath must equal the one we set.", storePath.getAbsolutePath(),
OmemoConfiguration.getFileBasedOmemoStoreDefaultPath().getAbsolutePath());
// EME
OmemoConfiguration.setAddEmeEncryptionHint(false);
assertEquals(false, OmemoConfiguration.getAddEmeEncryptionHint());
OmemoConfiguration.setAddEmeEncryptionHint(true);
assertEquals(true, OmemoConfiguration.getAddEmeEncryptionHint());
// MAM
OmemoConfiguration.setAddMAMStorageProcessingHint(false);
assertEquals(false, OmemoConfiguration.getAddMAMStorageProcessingHint());
OmemoConfiguration.setAddMAMStorageProcessingHint(true);
assertEquals(true, OmemoConfiguration.getAddMAMStorageProcessingHint());
// Body hint
OmemoConfiguration.setAddOmemoHintBody(false);
assertEquals(false, OmemoConfiguration.getAddOmemoHintBody());
OmemoConfiguration.setAddOmemoHintBody(true);
assertEquals(true, OmemoConfiguration.getAddOmemoHintBody());
// Delete stale devices
OmemoConfiguration.setDeleteStaleDevices(false);
assertEquals(false, OmemoConfiguration.getDeleteStaleDevices());
OmemoConfiguration.setDeleteStaleDevices(true);
assertEquals(true, OmemoConfiguration.getDeleteStaleDevices());
OmemoConfiguration.setDeleteStaleDevicesAfterHours(25);
assertEquals(25, OmemoConfiguration.getDeleteStaleDevicesAfterHours());
try {
OmemoConfiguration.setDeleteStaleDevicesAfterHours(-3);
TestCase.fail("OmemoConfiguration.setDeleteStaleDevicesAfterHours should not accept values <= 0.");
} catch (IllegalArgumentException e) {
// Expected.
}
// Ignore stale device
OmemoConfiguration.setIgnoreStaleDevices(false);
assertEquals(false, OmemoConfiguration.getIgnoreStaleDevices());
OmemoConfiguration.setIgnoreStaleDevices(true);
assertEquals(true, OmemoConfiguration.getIgnoreStaleDevices());
OmemoConfiguration.setIgnoreStaleDevicesAfterHours(44);
assertEquals(44, OmemoConfiguration.getIgnoreStaleDevicesAfterHours());
try {
OmemoConfiguration.setIgnoreStaleDevicesAfterHours(-5);
TestCase.fail("OmemoConfiguration.setIgnoreStaleDevicesAfterHours should not accept values <= 0.");
} catch (IllegalArgumentException e) {
// Expected
}
// Renew signedPreKeys
OmemoConfiguration.setRenewOldSignedPreKeys(false);
assertEquals(false, OmemoConfiguration.getRenewOldSignedPreKeys());
OmemoConfiguration.setRenewOldSignedPreKeys(true);
assertEquals(true, OmemoConfiguration.getRenewOldSignedPreKeys());
OmemoConfiguration.setRenewOldSignedPreKeysAfterHours(77);
assertEquals(77, OmemoConfiguration.getRenewOldSignedPreKeysAfterHours());
try {
OmemoConfiguration.setRenewOldSignedPreKeysAfterHours(0);
TestCase.fail("OmemoConfiguration.setRenewOldSignedPreKeysAfterHours should not accept values <= 0");
} catch (IllegalArgumentException e) {
// Expected
}
OmemoConfiguration.setMaxNumberOfStoredSignedPreKeys(6);
assertEquals(6, OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys());
try {
OmemoConfiguration.setMaxNumberOfStoredSignedPreKeys(0);
TestCase.fail("OmemoConfiguration.setMaxNumberOfStoredSignedPreKeys should not accept values <= 0");
} catch (IllegalArgumentException e) {
//Expected
}
}
}

View file

@ -0,0 +1,56 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListVAxolotlElement;
import org.jivesoftware.smackx.omemo.provider.OmemoDeviceListVAxolotlProvider;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import java.util.HashSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test serialization and parsing of DeviceListElement.
*/
public class OmemoDeviceListVAxolotlElementTest extends SmackTestSuite {
@Test
public void serializationTest() throws Exception {
HashSet<Integer> ids = new HashSet<>();
ids.add(1234);
ids.add(9876);
OmemoDeviceListVAxolotlElement element = new OmemoDeviceListVAxolotlElement(ids);
String xml = element.toXML().toString();
XmlPullParser parser = TestUtils.getParser(xml);
OmemoDeviceListVAxolotlElement parsed = new OmemoDeviceListVAxolotlProvider().parse(parser);
assertTrue("Parsed element must equal the original.", parsed.getDeviceIds().equals(element.getDeviceIds()));
assertEquals("Generated XML must match.",
"<list xmlns='eu.siacs.conversations.axolotl'>" +
"<device id='1234'/>" +
"<device id='9876'/>" +
"</list>",
xml);
}
}

View file

@ -0,0 +1,62 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.junit.Assert;
import org.junit.Test;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test the OmemoDevice class.
*
* @author Paul Schaub
*/
public class OmemoDeviceTest {
/**
* Test, if the equals() method works as intended.
*/
@Test
public void testEquals() {
BareJid romeo, juliet, guyUnderTheBalcony;
try {
romeo = JidCreate.bareFrom("romeo@shakespeare.lit");
guyUnderTheBalcony = JidCreate.bareFrom("romeo@shakespeare.lit/underTheBalcony");
juliet = JidCreate.bareFrom("juliet@shakespeare.lit");
} catch (XmppStringprepException e) {
Assert.fail(e.getMessage());
return;
}
OmemoDevice r = new OmemoDevice(romeo, 1);
OmemoDevice g = new OmemoDevice(guyUnderTheBalcony, 1);
OmemoDevice r2 = new OmemoDevice(romeo, 2);
OmemoDevice j = new OmemoDevice(juliet, 3);
OmemoDevice j2 = new OmemoDevice(juliet, 1);
assertTrue(r.equals(g));
assertFalse(r.equals(r2));
assertFalse(j.equals(j2));
assertFalse(j2.equals(r2));
}
}

View file

@ -0,0 +1,104 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
import org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException;
import org.jivesoftware.smackx.omemo.exceptions.UndecidedOmemoIdentityException;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.junit.Test;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import java.util.ArrayList;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test Omemo related Exceptions.
*/
public class OmemoExceptionsTest {
@Test
public void undecidedOmemoIdentityExceptionTest() throws XmppStringprepException {
OmemoDevice alice = new OmemoDevice(JidCreate.bareFrom("alice@server.tld"), 1234);
OmemoDevice bob = new OmemoDevice(JidCreate.bareFrom("bob@server.tld"), 5678);
OmemoDevice mallory = new OmemoDevice(JidCreate.bareFrom("mallory@server.tld"), 9876);
UndecidedOmemoIdentityException u = new UndecidedOmemoIdentityException(alice);
assertTrue(u.getUntrustedDevices().contains(alice));
assertTrue(u.getUntrustedDevices().size() == 1);
UndecidedOmemoIdentityException v = new UndecidedOmemoIdentityException(bob);
v.getUntrustedDevices().add(mallory);
assertTrue(v.getUntrustedDevices().size() == 2);
assertTrue(v.getUntrustedDevices().contains(bob));
assertTrue(v.getUntrustedDevices().contains(mallory));
u.getUntrustedDevices().add(bob);
u.join(v);
assertTrue(u.getUntrustedDevices().size() == 3);
}
@Test
public void cannotEstablishOmemoSessionExceptionTest() throws XmppStringprepException {
OmemoDevice alice1 = new OmemoDevice(JidCreate.bareFrom("alice@server.tld"), 1234);
OmemoDevice alice2 = new OmemoDevice(JidCreate.bareFrom("alice@server.tld"), 2345);
OmemoDevice bob = new OmemoDevice(JidCreate.bareFrom("bob@server.tld"), 5678);
CannotEstablishOmemoSessionException c = new CannotEstablishOmemoSessionException(alice1, null);
assertEquals(1, c.getFailures().size());
assertTrue(c.getFailures().containsKey(alice1.getJid()));
c.addSuccess(alice2);
assertFalse(c.requiresThrowing());
c.addFailures(new CannotEstablishOmemoSessionException(bob, null));
assertTrue(c.requiresThrowing());
assertEquals(1, c.getSuccesses().size());
assertEquals(2, c.getFailures().size());
c.getSuccesses().remove(alice2.getJid());
c.addFailures(new CannotEstablishOmemoSessionException(alice2, null));
assertEquals(2, c.getFailures().size());
}
@Test
public void multipleCryptoFailedExceptionTest() {
CryptoFailedException e1 = new CryptoFailedException("Fail");
CryptoFailedException e2 = new CryptoFailedException("EpicFail");
ArrayList<CryptoFailedException> l = new ArrayList<>();
l.add(e1); l.add(e2);
MultipleCryptoFailedException m = MultipleCryptoFailedException.from(l);
assertEquals(2, m.getCryptoFailedExceptions().size());
assertTrue(m.getCryptoFailedExceptions().contains(e1));
assertTrue(m.getCryptoFailedExceptions().contains(e2));
ArrayList<CryptoFailedException> el = new ArrayList<>();
try {
MultipleCryptoFailedException m2 = MultipleCryptoFailedException.from(el);
fail("MultipleCryptoFailedException must not allow empty list.");
} catch (IllegalArgumentException e) {
// Expected
}
}
}

View file

@ -0,0 +1,38 @@
/**
*
* 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.smack.omemo;
import org.jivesoftware.smackx.omemo.OmemoFingerprint;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotSame;
/**
* Test the OmemoFingerprint class.
*/
public class OmemoFingerprintTest {
@Test
public void fingerprintTest() {
OmemoFingerprint first = new OmemoFingerprint("FINGER");
OmemoFingerprint second = new OmemoFingerprint("TOE");
assertNotSame(first, second);
assertEquals(first, new OmemoFingerprint("FINGER"));
}
}

View file

@ -0,0 +1,46 @@
/**
*
* 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.smack.omemo;
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
/**
* Test KeyUtil functions.
*
* @author Paul Schaub
*/
public class OmemoKeyUtilTest {
@Test
public void testAddInBounds() {
int high = Integer.MAX_VALUE - 2;
int max = Integer.MAX_VALUE;
assertEquals(OmemoKeyUtil.addInBounds(high, 3), 1);
assertEquals(OmemoKeyUtil.addInBounds(1,2), 3);
assertEquals(OmemoKeyUtil.addInBounds(max, 5), 5);
}
@Test
public void testPrettyFingerprint() {
String ugly = "FFFFFFFFEEEEEEEEDDDDDDDDCCCCCCCCBBBBBBBBAAAAAAAA9999999988888888";
String pretty = OmemoKeyUtil.prettyFingerprint(ugly);
assertEquals(pretty, "FFFFFFFF EEEEEEEE DDDDDDDD CCCCCCCC BBBBBBBB AAAAAAAA 99999999 88888888");
}
}

View file

@ -0,0 +1,73 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement;
import org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider;
import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
import org.junit.Test;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
/**
* Test serialization and parsing of OmemoVAxolotlElements.
*/
public class OmemoVAxolotlElementTest extends SmackTestSuite {
@Test
public void serializationTest() throws Exception {
byte[] payload = "This is payload.".getBytes(StringUtils.UTF8);
int keyId1 = 8;
int keyId2 = 33333;
byte[] keyData1 = "KEYDATA".getBytes(StringUtils.UTF8);
byte[] keyData2 = "DATAKEY".getBytes(StringUtils.UTF8);
int sid = 12131415;
byte[] iv = OmemoMessageBuilder.generateIv();
ArrayList<OmemoElement.OmemoHeader.Key> keys = new ArrayList<>();
keys.add(new OmemoElement.OmemoHeader.Key(keyData1, keyId1));
keys.add(new OmemoElement.OmemoHeader.Key(keyData2, keyId2, true));
OmemoVAxolotlElement.OmemoHeader header = new OmemoElement.OmemoHeader(sid, keys, iv);
OmemoVAxolotlElement element = new OmemoVAxolotlElement(header, payload);
String expected =
"<encrypted xmlns='eu.siacs.conversations.axolotl'>" +
"<header sid='12131415'>" +
"<key rid='8'>" + Base64.encodeToString(keyData1) + "</key>" +
"<key prekey='true' rid='33333'>" + Base64.encodeToString(keyData2) + "</key>" +
"<iv>" + Base64.encodeToString(iv) + "</iv>" +
"</header>" +
"<payload>" +
Base64.encodeToString(payload) +
"</payload>" +
"</encrypted>";
String actual = element.toXML().toString();
assertEquals("Serialized xml of OmemoElement must match.", expected, actual);
OmemoVAxolotlElement parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual));
assertEquals("Parsed OmemoElement must equal the original.", element.toXML().toString(), parsed.toXML().toString());
}
}

View file

@ -0,0 +1,105 @@
/**
*
* Copyright the original author or authors
*
* 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.smack.omemo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
import org.jivesoftware.smackx.omemo.internal.CipherAndAuthTag;
import org.jivesoftware.smackx.omemo.internal.CiphertextTuple;
import org.jivesoftware.smackx.omemo.internal.ClearTextMessage;
import org.jivesoftware.smackx.omemo.internal.IdentityKeyWrapper;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.internal.OmemoMessageInformation;
import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
import org.junit.Test;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.impl.JidCreate;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
/**
* Test the identityKeyWrapper.
*/
public class WrapperObjectsTest {
@Test
public void identityKeyWrapperTest() {
Object pseudoKey = new Object();
IdentityKeyWrapper wrapper = new IdentityKeyWrapper(pseudoKey);
assertEquals(pseudoKey, wrapper.getIdentityKey());
}
@Test
public void ciphertextTupleTest() {
byte[] c = OmemoMessageBuilder.generateIv();
CiphertextTuple c1 = new CiphertextTuple(c, OmemoElement.TYPE_OMEMO_PREKEY_MESSAGE);
assertTrue(c1.isPreKeyMessage());
assertArrayEquals(c, c1.getCiphertext());
assertEquals(OmemoElement.TYPE_OMEMO_PREKEY_MESSAGE, c1.getMessageType());
CiphertextTuple c2 = new CiphertextTuple(c, OmemoElement.TYPE_OMEMO_MESSAGE);
assertFalse(c2.isPreKeyMessage());
assertEquals(OmemoElement.TYPE_OMEMO_MESSAGE, c2.getMessageType());
}
@Test
public void clearTextMessageTest() throws Exception {
Object pseudoKey = new Object();
IdentityKeyWrapper wrapper = new IdentityKeyWrapper(pseudoKey);
BareJid senderJid = JidCreate.bareFrom("bob@server.tld");
OmemoDevice sender = new OmemoDevice(senderJid, 1234);
OmemoMessageInformation information = new OmemoMessageInformation(wrapper, sender, OmemoMessageInformation.CARBON.NONE);
assertTrue("OmemoInformation must state that the message is an OMEMO message.",
information.isOmemoMessage());
assertEquals(OmemoMessageInformation.CARBON.NONE, information.getCarbon());
assertEquals(sender, information.getSenderDevice());
assertEquals(wrapper, information.getSenderIdentityKey());
String body = "Decrypted Body";
Message message = new Message(senderJid, body);
ClearTextMessage c = new ClearTextMessage(body, message, information);
assertEquals(message, c.getOriginalMessage());
assertEquals(information, c.getMessageInformation());
assertEquals(body, c.getBody());
}
@Test
public void cipherAndAuthTagTest() throws NoSuchAlgorithmException, CryptoFailedException {
Security.addProvider(new BouncyCastleProvider());
byte[] key = OmemoMessageBuilder.generateKey();
byte[] iv = OmemoMessageBuilder.generateIv();
byte[] authTag = OmemoMessageBuilder.generateIv();
CipherAndAuthTag cat = new CipherAndAuthTag(key, iv, authTag);
assertNotNull(cat.getCipher());
assertArrayEquals(key, cat.getKey());
assertArrayEquals(iv, cat.getIv());
assertArrayEquals(authTag, cat.getAuthTag());
}
}