mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-12-05 20:51:07 +01:00
Rework support for XEP-0384: OMEMO Encryption
Changes:
Rework integration tests
New structure of base integration test classes
bump dependency on signal-protocol-java from 2.4.0 to 2.6.2
Introduced CachingOmemoStore implementations
Use CachingOmemoStore classes in integration tests
Removed OmemoSession classes (replaced with more logical OmemoRatchet classes)
Consequently also removed load/storeOmemoSession methods from OmemoStore
Removed some clutter from KeyUtil classes
Moved trust decision related code from OmemoStore to TrustCallback
Require authenticated connection for many functions
Add async initialization function in OmemoStore
Refactor omemo test package (/java/org/jivesoftware/smack/omemo -> /java/org/jivesoftware/smackx)
Remove OmemoStore method isFreshInstallation() as well as defaultDeviceId related stuff
FileBasedOmemoStore: Add cleaner methods to store/load base data types (Using tryWithResource, only for future releases, once Android API gets bumped)
Attempt to make OmemoManager thread safe
new logic for getInstanceFor() deviceId determination
OmemoManagers encrypt methods now don't throw exceptions when encryption for some devices fails. Instead message gets encrypted when possible and more information about failures gets returned alongside the message itself
Added OmemoMessage class for that purpose
Reworked entire OmemoService class
Use safer logic for creating trust-ignoring messages (like ratchet-update messages)
Restructure elements/provider in order to prepare for OMEMO namespace bumps
Remove OmemoManager.regenerate() methods in favor of getInstanceFor(connection, randomDeviceId)
Removed some unnecessary configuration options
Prepare for support of more AES message key types
Simplify session creation
Where possible, avoid side effects in methods
Add UntrustedOmemoIdentityException
Add TrustState enum
More improved tests
This commit is contained in:
parent
f290197f6a
commit
1f731f6318
96 changed files with 6915 additions and 5488 deletions
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNotSame;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static junit.framework.TestCase.fail;
|
||||
|
||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoKeyUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* Test SignalOmemoKeyUtil methods.
|
||||
*
|
||||
* @author Paul Schaub
|
||||
*/
|
||||
public class LegacySignalOmemoKeyUtilTest extends SmackTestSuite {
|
||||
|
||||
private final SignalOmemoKeyUtil keyUtil = new SignalOmemoKeyUtil();
|
||||
|
||||
@Test
|
||||
public void omemoIdentityKeyPairSerializationTest() throws CorruptedOmemoKeyException {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
byte[] bytes = keyUtil.identityKeyPairToBytes(ikp);
|
||||
assertNotNull("serialized identityKeyPair must not be null.",
|
||||
bytes);
|
||||
assertNotSame("serialized identityKeyPair must not be of length 0.",
|
||||
0, bytes.length);
|
||||
|
||||
IdentityKeyPair ikp2 = keyUtil.identityKeyPairFromBytes(bytes);
|
||||
assertTrue("Deserialized IdentityKeyPairs PublicKey must equal the originals one.",
|
||||
ikp.getPublicKey().equals(ikp2.getPublicKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void omemoIdentityKeySerializationTest() {
|
||||
IdentityKey k = keyUtil.generateOmemoIdentityKeyPair().getPublicKey();
|
||||
|
||||
try {
|
||||
assertEquals("Deserialized IdentityKey must equal the original one.",
|
||||
k, keyUtil.identityKeyFromBytes(keyUtil.identityKeyToBytes(k)));
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
fail("Caught exception while serializing and deserializing identityKey (" + e + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateOmemoSignedPreKeyTest() {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
try {
|
||||
SignedPreKeyRecord spk = keyUtil.generateOmemoSignedPreKey(ikp, 1);
|
||||
assertNotNull("SignedPreKey must not be null.", spk);
|
||||
assertEquals("SignedPreKeyId must match.", 1, spk.getId());
|
||||
assertEquals("singedPreKeyId must match here also.", 1, keyUtil.signedPreKeyIdFromKey(spk));
|
||||
} catch (CorruptedOmemoKeyException e) {
|
||||
fail("Caught an exception while generating signedPreKey (" + e + "): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFingerprintTest() {
|
||||
IdentityKeyPair ikp = keyUtil.generateOmemoIdentityKeyPair();
|
||||
IdentityKey ik = ikp.getPublicKey();
|
||||
assertTrue("Length of fingerprint must be 64.",
|
||||
keyUtil.getFingerprintOfIdentityKey(ik).length() == 64);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoKeyUtil;
|
||||
import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* smack-omemo-signal implementation of {@link OmemoKeyUtilTest}.
|
||||
* This class executes tests of its super class with available implementations of {@link OmemoKeyUtil}.
|
||||
* So far this includes {@link SignalOmemoKeyUtil}.
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class SignalOmemoKeyUtilTest
|
||||
extends OmemoKeyUtilTest<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, ECPublicKey, PreKeyBundle> {
|
||||
|
||||
public SignalOmemoKeyUtilTest(OmemoKeyUtil<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, ECPublicKey, PreKeyBundle> keyUtil) {
|
||||
super(keyUtil);
|
||||
}
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> getParameters() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{ new SignalOmemoKeyUtil()}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.assertNotSame;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import org.jivesoftware.smack.DummyConnection;
|
||||
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.provider.OmemoVAxolotlProvider;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoService;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test OmemoManager functionality.
|
||||
*/
|
||||
public class SignalOmemoManagerTest extends SmackTestSuite {
|
||||
|
||||
@Test
|
||||
public void instantiationTest() {
|
||||
SignalOmemoService.acknowledgeLicense();
|
||||
SignalOmemoService.setup();
|
||||
|
||||
DummyConnection dummy = new DummyConnection();
|
||||
DummyConnection silly = new DummyConnection();
|
||||
OmemoManager a = OmemoManager.getInstanceFor(dummy, 123);
|
||||
OmemoManager b = OmemoManager.getInstanceFor(dummy, 234);
|
||||
OmemoManager c = OmemoManager.getInstanceFor(silly, 123);
|
||||
OmemoManager d = OmemoManager.getInstanceFor(dummy, 123);
|
||||
|
||||
assertNotNull(a);
|
||||
assertNotNull(b);
|
||||
assertNotNull(c);
|
||||
assertNotNull(d);
|
||||
|
||||
assertEquals(Integer.valueOf(123), a.getDeviceId());
|
||||
assertEquals(Integer.valueOf(234), b.getDeviceId());
|
||||
|
||||
assertFalse(a == b);
|
||||
assertFalse(a == c);
|
||||
assertFalse(b == c);
|
||||
assertTrue(a == d);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void randomDeviceIdTest() {
|
||||
int a = OmemoManager.randomDeviceId();
|
||||
int b = OmemoManager.randomDeviceId();
|
||||
|
||||
assertNotSame(a, b); // This is highly unlikely
|
||||
|
||||
assertTrue(a > 0);
|
||||
assertTrue(b > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stanzaRecognitionTest() throws Exception {
|
||||
String omemoXML = "<encrypted xmlns='eu.siacs.conversations.axolotl'><header sid='1009'><key rid='1337'>MwohBfRqBm2atj3fT0/KUDg59Cnvfpgoe/PLNIu1xgSXujEZEAAYACIwKh6TTC7VBQZcCcKnQlO+6s1GQ9DIRKH4JU7XrJ+JJnkPUwJ4VLSeOEQD7HmFbhQPTLZO0u/qlng=</key><iv>sN0amy4e2NBrlb4G/OjNIQ==</iv></header><payload>4xVUAeg4M0Mhk+5n3YG1x12Dw/cYTc0Z</payload></encrypted>";
|
||||
OmemoElement omemoElement = new OmemoVAxolotlProvider().parse(TestUtils.getParser(omemoXML));
|
||||
Message m = new Message();
|
||||
m.addExtension(omemoElement);
|
||||
Message n = new Message();
|
||||
|
||||
assertTrue(OmemoManager.stanzaContainsOmemoElement(m));
|
||||
assertFalse(OmemoManager.stanzaContainsOmemoElement(n));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoStoreConnector;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test some functionality of the SignalOmemoStoreConnector.
|
||||
*/
|
||||
public class SignalOmemoStoreConnectorTest {
|
||||
|
||||
@Test
|
||||
public void getLocalRegistrationIdTest() {
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(null, null);
|
||||
assertEquals("RegistrationId must always be 0.", 0, connector.getLocalRegistrationId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isTrustedIdentityTest() {
|
||||
SignalOmemoStoreConnector connector = new SignalOmemoStoreConnector(null, null);
|
||||
assertTrue("All identities must be trusted by default.", connector.isTrustedIdentity(null, null, null));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2017 Paul Schaub
|
||||
*
|
||||
* This file is part of smack-omemo-signal.
|
||||
*
|
||||
* smack-omemo-signal is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.jivesoftware.smackx.omemo;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalCachingOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalFileBasedOmemoStore;
|
||||
import org.jivesoftware.smackx.omemo.signal.SignalOmemoKeyUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.SessionCipher;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.ecc.ECPublicKey;
|
||||
import org.whispersystems.libsignal.state.PreKeyBundle;
|
||||
import org.whispersystems.libsignal.state.PreKeyRecord;
|
||||
import org.whispersystems.libsignal.state.SessionRecord;
|
||||
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
|
||||
|
||||
/**
|
||||
* smack-omemo-signal implementation of {@link OmemoStoreTest}.
|
||||
* This class executes tests of its super class with available implementations of {@link OmemoStore}.
|
||||
* So far this includes {@link SignalFileBasedOmemoStore}, {@link SignalCachingOmemoStore}.
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class SignalOmemoStoreTest extends OmemoStoreTest<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> {
|
||||
|
||||
public SignalOmemoStoreTest(OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store)
|
||||
throws XmppStringprepException {
|
||||
super(store);
|
||||
}
|
||||
|
||||
/**
|
||||
* We are running this Test with multiple available OmemoStore implementations.
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> getParameters() throws IOException {
|
||||
TemporaryFolder temp = initStaticTemp();
|
||||
return Arrays.asList(new Object[][] {
|
||||
// Simple file based store
|
||||
{ new SignalFileBasedOmemoStore(temp.newFolder("sigFileBased"))},
|
||||
// Ephemeral caching store
|
||||
{ new SignalCachingOmemoStore()},
|
||||
// Caching file based store
|
||||
{ new SignalCachingOmemoStore(new SignalFileBasedOmemoStore(temp.newFolder("cachingSigFileBased")))}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyUtilTest() {
|
||||
assertTrue(store.keyUtil() instanceof SignalOmemoKeyUtil);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue