1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-23 20:42:06 +01:00

Temp commit

This commit is contained in:
Paul Schaub 2017-12-24 02:52:41 +01:00
parent 0530449e7e
commit b0acf0bcc3
27 changed files with 740 additions and 744 deletions

View file

@ -24,7 +24,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.TreeMap; import java.util.TreeMap;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice; import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
@ -141,7 +141,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
} }
@Override @Override
public PreKeyBundle bundleFromOmemoBundle(OmemoBundleVAxolotlElement bundle, OmemoDevice contact, int preKeyId) public PreKeyBundle bundleFromOmemoBundle(OmemoBundleElement bundle, OmemoDevice contact, int preKeyId)
throws CorruptedOmemoKeyException throws CorruptedOmemoKeyException
{ {
return new PreKeyBundle(0, return new PreKeyBundle(0,

View file

@ -55,9 +55,8 @@ import org.jivesoftware.smackx.mam.MamManager;
import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager; import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.muc.RoomInfo; import org.jivesoftware.smackx.muc.RoomInfo;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
@ -148,9 +147,11 @@ public final class OmemoManager extends Manager {
* Return an OmemoManager instance for the given connection and deviceId. * Return an OmemoManager instance for the given connection and deviceId.
* If there was an OmemoManager for the connection and id before, return it. Otherwise create a new OmemoManager * If there was an OmemoManager for the connection and id before, return it. Otherwise create a new OmemoManager
* instance and return it. * instance and return it.
*
* @param connection XmppConnection. * @param connection XmppConnection.
* @param deviceId MUST NOT be null and MUST be greater than 0. * @param deviceId MUST NOT be null and MUST be greater than 0.
* @return *
* @return manager
*/ */
public synchronized static OmemoManager getInstanceFor(XMPPConnection connection, Integer deviceId) { public synchronized static OmemoManager getInstanceFor(XMPPConnection connection, Integer deviceId) {
if (deviceId == null || deviceId < 1) { if (deviceId == null || deviceId < 1) {
@ -173,10 +174,14 @@ public final class OmemoManager extends Manager {
} }
/** /**
* Returns an OmemoManager instance for the given connection. If there was no OmemoManager for that connection * Returns an OmemoManager instance for the given connection. If there was one manager for the connection before,
* before, create a new one. If there was one before, return it. If there were multiple managers before, return the * return it. If there were multiple managers before, return the one with the lowest deviceId.
* one with the lowest deviceId. * If there was no manager before, return a new one. As soon as the connection gets authenticated, the manager
* will look for local deviceIDs and select the lowest one as its id. If there are not local deviceIds, the manager
* will assign itself a random id.
*
* @param connection XmppConnection. * @param connection XmppConnection.
*
* @return manager * @return manager
*/ */
public synchronized static OmemoManager getInstanceFor(XMPPConnection connection) { public synchronized static OmemoManager getInstanceFor(XMPPConnection connection) {
@ -201,7 +206,9 @@ public final class OmemoManager extends Manager {
/** /**
* Set a TrustCallback for this particular OmemoManager. * Set a TrustCallback for this particular OmemoManager.
* @param callback trustCallback used to query and modify trust states. * TrustCallbacks are used to query and modify trust decisions.
*
* @param callback trustCallback.
*/ */
public void setTrustCallback(TrustCallback callback) { public void setTrustCallback(TrustCallback callback) {
if (trustCallback != null) { if (trustCallback != null) {
@ -237,7 +244,8 @@ public final class OmemoManager extends Manager {
/** /**
* Initialize the manager without blocking. Once the manager is successfully initialized, the finishedCallback will * Initialize the manager without blocking. Once the manager is successfully initialized, the finishedCallback will
* be notified. It will also get notified, if an error occurs. * be notified. It will also get notified, if an error occurs.
* @param finishedCallback *
* @param finishedCallback callback that gets called once the manager is initialized.
*/ */
public void initializeAsync(final FinishedCallback finishedCallback) { public void initializeAsync(final FinishedCallback finishedCallback) {
Async.go(new Runnable() { Async.go(new Runnable() {
@ -257,7 +265,7 @@ public final class OmemoManager extends Manager {
* OMEMO encrypt a cleartext message for a single recipient. * OMEMO encrypt a cleartext message for a single recipient.
* Note that this method does NOT set the 'to' attribute of the message. * Note that this method does NOT set the 'to' attribute of the message.
* *
* @param to recipients barejid * @param to recipients bareJid
* @param message text to encrypt * @param message text to encrypt
* @return encrypted message * @return encrypted message
* @throws CryptoFailedException when something crypto related fails * @throws CryptoFailedException when something crypto related fails
@ -278,7 +286,7 @@ public final class OmemoManager extends Manager {
LoggedInOmemoManager guard = new LoggedInOmemoManager(this); LoggedInOmemoManager guard = new LoggedInOmemoManager(this);
Message plaintext = new Message(); Message plaintext = new Message();
plaintext.setBody(message); plaintext.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService().processSendingMessage(guard, to, plaintext); OmemoElement encrypted = getOmemoService().processSendingMessage(guard, to, plaintext);
return finishMessage(encrypted); return finishMessage(encrypted);
} }
} }
@ -306,7 +314,7 @@ public final class OmemoManager extends Manager {
synchronized (LOCK) { synchronized (LOCK) {
Message m = new Message(); Message m = new Message();
m.setBody(message); m.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService().processSendingMessage( OmemoElement encrypted = getOmemoService().processSendingMessage(
new LoggedInOmemoManager(this), recipients, m); new LoggedInOmemoManager(this), recipients, m);
return finishMessage(encrypted); return finishMessage(encrypted);
} }
@ -368,7 +376,7 @@ public final class OmemoManager extends Manager {
synchronized (LOCK) { synchronized (LOCK) {
Message m = new Message(); Message m = new Message();
m.setBody(message); m.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService() OmemoElement encrypted = getOmemoService()
.encryptOmemoMessage(new LoggedInOmemoManager(this), exception.getSuccesses(), m); .encryptOmemoMessage(new LoggedInOmemoManager(this), exception.getSuccesses(), m);
return finishMessage(encrypted); return finishMessage(encrypted);
} }
@ -482,43 +490,6 @@ public final class OmemoManager extends Manager {
return trustCallback.getTrust(device, fingerprint) != TrustState.undecided; return trustCallback.getTrust(device, fingerprint) != TrustState.undecided;
} }
/**
* Clear all other devices except this one from our device list and republish the list.
*
* @throws InterruptedException
* @throws SmackException
* @throws XMPPException.XMPPErrorException
* @throws CorruptedOmemoKeyException
*/
public void purgeDeviceList()
throws SmackException, InterruptedException, XMPPException.XMPPErrorException, CorruptedOmemoKeyException
{
synchronized (LOCK) {
LoggedInOmemoManager managerGuard = new LoggedInOmemoManager(this);
getOmemoService().publishDeviceIdIfNeeded(managerGuard, true);
getOmemoService().publishBundle(managerGuard);
}
}
/**
* Generate fresh identity keys and bundle and publish it to the server.
* @throws SmackException
* @throws InterruptedException
* @throws XMPPException.XMPPErrorException
* @throws CorruptedOmemoKeyException
*/
public void regenerateIdentity()
throws SmackException, InterruptedException, XMPPException.XMPPErrorException, CorruptedOmemoKeyException
{
synchronized (LOCK) {
LoggedInOmemoManager managerGuard = new LoggedInOmemoManager(this);
// create a new identity and publish new keys to the server
getOmemoService().regenerate(managerGuard);
getOmemoService().publishDeviceIdIfNeeded(managerGuard, false);
getOmemoService().publishBundle(managerGuard);
}
}
/** /**
* Send a ratchet update message. This can be used to advance the ratchet of a session in order to maintain forward * Send a ratchet update message. This can be used to advance the ratchet of a session in order to maintain forward
* secrecy. * secrecy.
@ -552,7 +523,7 @@ public final class OmemoManager extends Manager {
* @throws CryptoFailedException When something fails with the crypto * @throws CryptoFailedException When something fails with the crypto
* @throws CannotEstablishOmemoSessionException When we can't establish a session with the recipient * @throws CannotEstablishOmemoSessionException When we can't establish a session with the recipient
*/ */
public OmemoVAxolotlElement createKeyTransportElement(byte[] aesKey, byte[] iv, OmemoDevice ... to) public OmemoElement createKeyTransportElement(byte[] aesKey, byte[] iv, OmemoDevice ... to)
throws UndecidedOmemoIdentityException, CorruptedOmemoKeyException, CryptoFailedException, throws UndecidedOmemoIdentityException, CorruptedOmemoKeyException, CryptoFailedException,
CannotEstablishOmemoSessionException, SmackException.NotLoggedInException CannotEstablishOmemoSessionException, SmackException.NotLoggedInException
{ {
@ -571,7 +542,7 @@ public final class OmemoManager extends Manager {
* @param encrypted OmemoMessageElement * @param encrypted OmemoMessageElement
* @return Message containing the OMEMO element and some additional information * @return Message containing the OMEMO element and some additional information
*/ */
Message finishMessage(OmemoVAxolotlElement encrypted) { Message finishMessage(OmemoElement encrypted) {
if (encrypted == null) { if (encrypted == null) {
return null; return null;
} }
@ -794,8 +765,7 @@ public final class OmemoManager extends Manager {
// generate key // generate key
getOmemoService().getOmemoStoreBackend().changeSignedPreKey(getOwnDevice()); getOmemoService().getOmemoStoreBackend().changeSignedPreKey(getOwnDevice());
// publish // publish
getOmemoService().publishDeviceIdIfNeeded(managerGuard, false); getOmemoService().publish(managerGuard);
getOmemoService().publishBundle(managerGuard);
} }
} }
@ -805,7 +775,7 @@ public final class OmemoManager extends Manager {
* @return true if stanza has extension 'encrypted' * @return true if stanza has extension 'encrypted'
*/ */
public static boolean stanzaContainsOmemoElement(Stanza stanza) { public static boolean stanzaContainsOmemoElement(Stanza stanza) {
return stanza.hasExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL); return stanza.hasExtension(OmemoElement.NAME_ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
} }
/** /**
@ -1013,13 +983,13 @@ public final class OmemoManager extends Manager {
PayloadItem<?> payloadItem = (PayloadItem<?>) item; PayloadItem<?> payloadItem = (PayloadItem<?>) item;
if (!(payloadItem.getPayload() instanceof OmemoDeviceListVAxolotlElement)) { if (!(payloadItem.getPayload() instanceof OmemoDeviceListElement_VAxolotl)) {
continue; continue;
} }
// Device List <list> // Device List <list>
OmemoDeviceListVAxolotlElement omemoDeviceListElement = OmemoDeviceListElement_VAxolotl omemoDeviceListElement =
(OmemoDeviceListVAxolotlElement) payloadItem.getPayload(); (OmemoDeviceListElement_VAxolotl) payloadItem.getPayload();
Integer ourDeviceId = getDeviceId(); Integer ourDeviceId = getDeviceId();
getOmemoService().getOmemoStoreBackend() getOmemoService().getOmemoStoreBackend()
@ -1047,8 +1017,8 @@ public final class OmemoManager extends Manager {
// enroll at the deviceList // enroll at the deviceList
deviceListIds.add(ourDeviceId); deviceListIds.add(ourDeviceId);
final OmemoDeviceListVAxolotlElement newOmemoDeviceListElement = final OmemoDeviceListElement_VAxolotl newOmemoDeviceListElement =
new OmemoDeviceListVAxolotlElement(deviceListIds); new OmemoDeviceListElement_VAxolotl(deviceListIds);
// PEPListener is a synchronous listener. // PEPListener is a synchronous listener.
// Avoid any deadlocks by using an async task to update the device list. // Avoid any deadlocks by using an async task to update the device list.

View file

@ -27,6 +27,7 @@ import javax.crypto.IllegalBlockSizeException;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
import org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.MultipleCryptoFailedException;
@ -67,9 +68,13 @@ public abstract class OmemoRatchet<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
int keyId = omemoManager.getDeviceId(); int keyId = omemoManager.getDeviceId();
byte[] unpackedKey = null; byte[] unpackedKey = null;
List<CryptoFailedException> decryptExceptions = new ArrayList<>(); List<CryptoFailedException> decryptExceptions = new ArrayList<>();
List<OmemoElement.OmemoHeader.Key> keys = element.getHeader().getKeys(); // CHECKSTYLE: OFF
@SuppressWarnings("unchecked")
List<OmemoKeyElement> keys = element.getHeader().getKeys();
// CHECKSTYLE: ON
// Find key with our ID. // Find key with our ID.
for (OmemoElement.OmemoHeader.Key k : keys) { for (OmemoKeyElement k : keys) {
if (k.getId() == keyId) { if (k.getId() == keyId) {
try { try {
unpackedKey = doubleRatchetDecrypt(sender, k.getData()); unpackedKey = doubleRatchetDecrypt(sender, k.getData());

View file

@ -30,7 +30,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -56,11 +55,10 @@ import org.jivesoftware.smackx.mam.MamManager;
import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatManager; import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.omemo.element.OmemoBundleElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
@ -206,6 +204,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
checkAvailableAlgorithms(); checkAvailableAlgorithms();
} }
/**
* Makes the OmemoManager known to the OmemoService.
* @param manager manager.
*/
void registerManager(OmemoManager manager) { void registerManager(OmemoManager manager) {
omemoRatchets.put(manager, instantiateOmemoRatchet(manager, getOmemoStoreBackend())); omemoRatchets.put(manager, instantiateOmemoRatchet(manager, getOmemoStoreBackend()));
} }
@ -219,7 +221,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws XMPPException.XMPPErrorException * @throws XMPPException.XMPPErrorException
* @throws SmackException.NotConnectedException * @throws SmackException.NotConnectedException
* @throws SmackException.NoResponseException * @throws SmackException.NoResponseException
* @throws SmackException.NotLoggedInException
* @throws PubSubException.NotALeafNodeException * @throws PubSubException.NotALeafNodeException
*/ */
void publish(OmemoManager.LoggedInOmemoManager managerGuard) void publish(OmemoManager.LoggedInOmemoManager managerGuard)
@ -227,12 +228,19 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
SmackException.NotConnectedException, SmackException.NoResponseException, SmackException.NotConnectedException, SmackException.NoResponseException,
PubSubException.NotALeafNodeException PubSubException.NotALeafNodeException
{ {
OmemoManager manager = managerGuard.get();
OmemoDevice userDevice = manager.getOwnDevice();
// Create new keys if necessary and publish to the server. // Create new keys if necessary and publish to the server.
publishBundle(managerGuard); publishBundle(managerGuard);
// Get fresh device list from server // Get fresh device list from server
refreshOwnDeviceList(managerGuard); CachedDeviceList list = refreshOwnDeviceList(managerGuard);
publishDeviceIdIfNeeded(managerGuard, false); if (!list.isActive(userDevice.getDeviceId())) {
list.addDevice(userDevice.getDeviceId());
}
publishDeviceIds(managerGuard, new OmemoDeviceListElement_VAxolotl(list.getActiveDevices()));
} }
/** /**
@ -256,32 +264,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
new OmemoMessageBuilder<>(null, null, ""); new OmemoMessageBuilder<>(null, null, "");
} }
/**
* Generate a new unique deviceId and regenerate new keys.
*
* @param managerGuard OmemoManager we want to regenerate.
* @throws CorruptedOmemoKeyException when freshly generated identityKey is invalid
* (should never ever happen *crosses fingers*)
*/
void regenerate(OmemoManager.LoggedInOmemoManager managerGuard)
throws CorruptedOmemoKeyException, InterruptedException, PubSubException.NotALeafNodeException,
XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException {
OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice();
int nDeviceId = OmemoManager.randomDeviceId();
// Generate unique ID that is not already taken
while (!getOmemoStoreBackend().isAvailableDeviceId(userDevice, nDeviceId)) {
nDeviceId = OmemoManager.randomDeviceId();
}
getOmemoStoreBackend().purgeOwnDeviceKeys(userDevice);
omemoManager.setDeviceId(nDeviceId);
publish(managerGuard);
}
/** /**
* Publish a bundle to the server. * Publish a bundle to the server.
* *
@ -319,70 +301,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
new PayloadItem<>(bundleElement)); new PayloadItem<>(bundleElement));
} }
/**
* Publish our deviceId in case it is not on the list already.
* This method calls publishDeviceIdIfNeeded(omemoManager, deleteOtherDevices, false).
* @param managerGuard OmemoManager
* @param deleteOtherDevices Do we want to remove other devices from the list?
* @throws InterruptedException
* @throws PubSubException.NotALeafNodeException
* @throws XMPPException.XMPPErrorException
* @throws SmackException.NotConnectedException
* @throws SmackException.NoResponseException
*/
void publishDeviceIdIfNeeded(OmemoManager.LoggedInOmemoManager managerGuard, boolean deleteOtherDevices)
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException
{
publishDeviceIdIfNeeded(managerGuard, deleteOtherDevices, false);
}
/**
* Publish our deviceId in case it is not on the list already.
*
* @param managerGuard OmemoManager
* @param deleteOtherDevices Do we want to remove other devices from the list?
* If we do, publish the list with only our id, regardless if we were on the list
* already.
* @param publish Do we want to force publishing our id?
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
* @throws XMPPException.XMPPErrorException
* @throws PubSubException.NotALeafNodeException
*/
void publishDeviceIdIfNeeded(OmemoManager.LoggedInOmemoManager managerGuard, boolean deleteOtherDevices, boolean publish)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
XMPPException.XMPPErrorException, PubSubException.NotALeafNodeException
{
OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice();
CachedDeviceList deviceList = getOmemoStoreBackend().loadCachedDeviceList(userDevice, userDevice.getJid());
Set<Integer> deviceListIds;
if (deviceList == null) {
deviceListIds = new HashSet<>();
} else {
deviceListIds = new HashSet<>(deviceList.getActiveDevices());
}
if (deleteOtherDevices) {
deviceListIds.clear();
}
int ourDeviceId = omemoManager.getDeviceId();
if (deviceListIds.add(ourDeviceId)) {
publish = true;
}
publish |= removeStaleDevicesIfNeeded(managerGuard, deviceListIds);
if (publish) {
publishDeviceIds(managerGuard, new OmemoDeviceListVAxolotlElement(deviceListIds));
}
}
/** /**
* Remove stale devices from our device list. * Remove stale devices from our device list.
* This does only delete devices, if that's configured in OmemoConfiguration. * This does only delete devices, if that's configured in OmemoConfiguration.
@ -432,11 +350,11 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
*omemoManager.getOwnJid() *omemoManager.getOwnJid()
* @param managerGuard OmemoManager * @param managerGuard OmemoManager
* @param deviceList list of deviceIDs * @param deviceList list of deviceIDs
* @throws InterruptedException Exception * @throws InterruptedException Exception
* @throws XMPPException.XMPPErrorException Exception * @throws XMPPException.XMPPErrorException Exception
* @throws SmackException.NotConnectedException Exception * @throws SmackException.NotConnectedException Exception
* @throws SmackException.NoResponseException Exception * @throws SmackException.NoResponseException Exception
* @throws PubSubException.NotALeafNodeException Exception * @throws PubSubException.NotALeafNodeException Exception
*/ */
static void publishDeviceIds(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDeviceListElement deviceList) static void publishDeviceIds(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDeviceListElement deviceList)
throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException,
@ -482,39 +400,17 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws NotAPubSubNodeException * @throws NotAPubSubNodeException
*/ */
static OmemoDeviceListElement fetchDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact) static OmemoDeviceListElement fetchDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, throws InterruptedException, SmackException.NotConnectedException, SmackException.NoResponseException,
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException XMPPException.XMPPErrorException {
{
return extractDeviceListFrom(fetchDeviceListNode(managerGuard, contact));
}
/**
* Refresh our deviceList from the server.
*
* @param managerGuard omemoManager
* @return true, if we should publish our device list again (because its broken or not existent...)
*
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
*/
private boolean refreshOwnDeviceList(OmemoManager.LoggedInOmemoManager managerGuard)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
XMPPException.XMPPErrorException
{
OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice();
try { try {
getOmemoStoreBackend().mergeCachedDeviceList(userDevice, userDevice.getJid(), return extractDeviceListFrom(fetchDeviceListNode(managerGuard, contact));
fetchDeviceList(managerGuard, omemoManager.getOwnJid())); }
} catch (XMPPException.XMPPErrorException e) { catch (XMPPException.XMPPErrorException e) {
if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) { if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) {
LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the node did not exist: " LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the node did not exist: "
+ e.getMessage()); + e.getMessage());
return true;
} }
throw e; throw e;
@ -522,15 +418,35 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
} catch (PubSubException.NotALeafNodeException e) { } catch (PubSubException.NotALeafNodeException e) {
LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the Node is not a LeafNode: " + LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the Node is not a LeafNode: " +
e.getMessage()); e.getMessage());
return true;
} }
catch (PubSubException.NotAPubSubNodeException e) { catch (PubSubException.NotAPubSubNodeException e) {
LOGGER.log(Level.WARNING, "Caught a PubSubAssertionError when fetching a deviceList node. " + LOGGER.log(Level.WARNING, "Caught a NotAPubSubNodeException when fetching a deviceList node. " +
"This probably means that we're dealing with an ejabberd server and the LeafNode does not exist."); "This probably means that we're dealing with an ejabberd server and the LeafNode does not exist.");
return true;
} }
return false; return null;
}
/**
* Refresh our deviceList from the server.
*
* @param managerGuard omemoManager
* @return true, if we should publish our device list again (because its broken or not existent or
* doesn't contain our id...)
*
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
*/
private CachedDeviceList refreshOwnDeviceList(OmemoManager.LoggedInOmemoManager managerGuard)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
XMPPException.XMPPErrorException
{
OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice();
OmemoDeviceListElement list = fetchDeviceList(managerGuard, omemoManager.getOwnJid());
return getOmemoStoreBackend().mergeCachedDeviceList(userDevice, userDevice.getJid(), list);
} }
/** /**
@ -541,20 +457,18 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws InterruptedException * @throws InterruptedException
* @throws SmackException.NoResponseException * @throws SmackException.NoResponseException
*/ */
void refreshDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact) CachedDeviceList refreshDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException
{ {
OmemoDeviceListElement omemoDeviceListElement; OmemoDeviceListElement omemoDeviceListElement = null;
try { try {
omemoDeviceListElement = fetchDeviceList(managerGuard, contact); omemoDeviceListElement = fetchDeviceList(managerGuard, contact);
} catch (XMPPException.XMPPErrorException e) {
} catch (PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | NotAPubSubNodeException e) {
LOGGER.log(Level.WARNING, "Could not fetch device list of " + contact + ": " + e); LOGGER.log(Level.WARNING, "Could not fetch device list of " + contact + ": " + e);
return;
} }
getOmemoStoreBackend().mergeCachedDeviceList(managerGuard.get().getOwnDevice(), contact, omemoDeviceListElement); return getOmemoStoreBackend().mergeCachedDeviceList(managerGuard.get().getOwnDevice(), contact, omemoDeviceListElement);
} }
/** /**
@ -570,13 +484,13 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws PubSubException.NotALeafNodeException when the bundles node is not a LeafNode * @throws PubSubException.NotALeafNodeException when the bundles node is not a LeafNode
* @throws NotAPubSubNodeException * @throws NotAPubSubNodeException
*/ */
static OmemoBundleVAxolotlElement fetchBundle(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contact) static OmemoBundleElement fetchBundle(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contact)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException
{ {
OmemoManager omemoManager = managerGuard.get(); OmemoManager omemoManager = managerGuard.get();
LeafNode node = PubSubManager.getInstance(omemoManager.getConnection(), contact.getJid()).getLeafNode( LeafNode node = PubSubManager.getInstance(omemoManager.getConnection(), contact.getJid()).getLeafNode(
PEP_NODE_BUNDLE_FROM_DEVICE_ID(contact.getDeviceId())); PEP_NODE_BUNDLE_FROM_DEVICE_ID(contact.getDeviceId()));
return extractBundleFrom(node); return extractBundleFrom(node);
} }
@ -590,22 +504,26 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws InterruptedException goes * @throws InterruptedException goes
* @throws SmackException.NoResponseException wrong * @throws SmackException.NoResponseException wrong
*/ */
private static OmemoBundleVAxolotlElement extractBundleFrom(LeafNode node) private static OmemoBundleElement extractBundleFrom(LeafNode node)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException SmackException.NoResponseException
{ {
if (node == null) { if (node == null) {
return null; return null;
} }
try {
return (OmemoBundleVAxolotlElement) ((PayloadItem<?>) node.getItems().get(0)).getPayload(); List<PayloadItem<OmemoBundleElement>> bundleItems = node.getItems();
} catch (IndexOutOfBoundsException e) { if (bundleItems.isEmpty()) {
return null; return null;
} }
return bundleItems.get(0).getPayload();
} }
/** /**
* Extract the OmemoDeviceListElement of a contact from a node containing his OmemoDeviceListElement. * Extract the OmemoDeviceListElement of a contact from a node containing his OmemoDeviceListElement.
* This method also ensures, that the node only contains one item. If there are more than one item in the node,
* all items are deleted and the list gets published again.
* *
* @param node typically a LeafNode containing the OmemoDeviceListElement of a contact * @param node typically a LeafNode containing the OmemoDeviceListElement of a contact
* @return the extracted OmemoDeviceListElement. * @return the extracted OmemoDeviceListElement.
@ -623,11 +541,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
return null; return null;
} }
List<?> items = node.getItems(); List<PayloadItem<OmemoDeviceListElement>> items = node.getItems();
if (items.size() > 0) { if (items.size() > 0) {
OmemoDeviceListVAxolotlElement listElement = OmemoDeviceListElement listElement = items.get(items.size() - 1).getPayload();
(OmemoDeviceListVAxolotlElement) ((PayloadItem<?>) items.get(items.size() - 1)).getPayload();
if (items.size() > 1) { if (items.size() > 1) {
node.deleteAllItems(); node.deleteAllItems();
@ -638,7 +555,42 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
} }
Set<Integer> emptySet = Collections.emptySet(); Set<Integer> emptySet = Collections.emptySet();
return new OmemoDeviceListVAxolotlElement(emptySet); return new OmemoDeviceListElement_VAxolotl(emptySet);
}
/**
* Build sessions for all devices of the contacts in the list, of which we have no session yet.
* When there are devices, this method throws a {@link CannotEstablishOmemoSessionException} which contains all
* those devices, while still establishing sessions with all other devices.
*
* @param managerGuard manager
* @param jids list of BareJids
* @throws SmackException.NotConnectedException
* @throws InterruptedException
* @throws SmackException.NoResponseException
* @throws CannotEstablishOmemoSessionException if we cannot create sessions with some devices.
*/
void buildMissingOmemoSessions(OmemoManager.LoggedInOmemoManager managerGuard, List<BareJid> jids)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
CannotEstablishOmemoSessionException {
CannotEstablishOmemoSessionException ex = null;
for (BareJid jid : jids) {
try {
buildMissingOmemoSessions(managerGuard, jid);
} catch (CannotEstablishOmemoSessionException e) {
if (ex == null) {
ex = e;
} else {
ex.addFailures(e);
}
}
}
if (ex != null) {
throw ex;
}
} }
/** /**
@ -724,7 +676,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
return; return;
} }
OmemoBundleVAxolotlElement bundle; OmemoBundleElement bundle;
try { try {
bundle = fetchBundle(managerGuard, contactsDevice); bundle = fetchBundle(managerGuard, contactsDevice);
} catch (SmackException | XMPPException.XMPPErrorException | InterruptedException e) { } catch (SmackException | XMPPException.XMPPErrorException | InterruptedException e) {
@ -758,7 +710,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* device, return null. * device, return null.
* *
* @param contactsDevice OmemoDevice of the sender of the message * @param contactsDevice OmemoDevice of the sender of the message
* @param message the encrypted message * @param omemoElement the encrypted message
* @param information OmemoMessageInformation object which will contain meta data about the decrypted message * @param information OmemoMessageInformation object which will contain meta data about the decrypted message
* @return decrypted message or null * @return decrypted message or null
* @throws NoRawSessionException * @throws NoRawSessionException
@ -771,7 +723,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
*/ */
private Message processReceivingMessage(OmemoManager.LoggedInOmemoManager managerGuard, private Message processReceivingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
OmemoDevice contactsDevice, OmemoDevice contactsDevice,
OmemoElement message, OmemoElement omemoElement,
final OmemoMessageInformation information) final OmemoMessageInformation information)
throws NoRawSessionException, InterruptedException, SmackException.NoResponseException, throws NoRawSessionException, InterruptedException, SmackException.NoResponseException,
SmackException.NotConnectedException, CryptoFailedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, CryptoFailedException, XMPPException.XMPPErrorException,
@ -780,15 +732,19 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
OmemoManager omemoManager = managerGuard.get(); OmemoManager omemoManager = managerGuard.get();
OmemoDevice userDevice = omemoManager.getOwnDevice(); OmemoDevice userDevice = omemoManager.getOwnDevice();
ArrayList<OmemoVAxolotlElement.OmemoHeader.Key> messageRecipientKeys = message.getHeader().getKeys(); // CHECKSTYLE: OFF
@SuppressWarnings("unchecked")
ArrayList<OmemoKeyElement> messageRecipientKeys = omemoElement.getHeader().getKeys();
// CHECKSTYLE: ON
// Do we have a key with our ID in the message? // Do we have a key with our ID in the message?
for (OmemoVAxolotlElement.OmemoHeader.Key k : messageRecipientKeys) { for (OmemoKeyElement k : messageRecipientKeys) {
// Only decrypt with our deviceID // Only decrypt with our deviceID
if (k.getId() != omemoManager.getDeviceId()) { if (k.getId() != omemoManager.getDeviceId()) {
continue; continue;
} }
Message decrypted = decryptOmemoMessageElement(managerGuard, contactsDevice, message, information); Message decrypted = decryptOmemoMessageElement(managerGuard, contactsDevice, omemoElement, information);
if (contactsDevice.equals(omemoManager.getOwnJid()) && decrypted != null) { if (contactsDevice.equals(omemoManager.getOwnJid()) && decrypted != null) {
getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, contactsDevice, new Date()); getOmemoStoreBackend().setDateOfLastReceivedMessage(userDevice, contactsDevice, new Date());
} }
@ -823,7 +779,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
CryptoFailedException, XMPPException.XMPPErrorException, CorruptedOmemoKeyException, NoRawSessionException CryptoFailedException, XMPPException.XMPPErrorException, CorruptedOmemoKeyException, NoRawSessionException
{ {
if (OmemoManager.stanzaContainsOmemoElement(message)) { if (OmemoManager.stanzaContainsOmemoElement(message)) {
OmemoElement omemoMessageElement = message.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL); OmemoElement omemoMessageElement = message.getExtension(OmemoElement.NAME_ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
OmemoMessageInformation info = new OmemoMessageInformation(); OmemoMessageInformation info = new OmemoMessageInformation();
Message decrypted = processReceivingMessage(managerGuard, Message decrypted = processReceivingMessage(managerGuard,
new OmemoDevice(sender, omemoMessageElement.getHeader().getSid()), new OmemoDevice(sender, omemoMessageElement.getHeader().getSid()),
@ -847,9 +803,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws UndecidedOmemoIdentityException * @throws UndecidedOmemoIdentityException
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
*/ */
OmemoVAxolotlElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard, OmemoElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
BareJid recipient, BareJid recipient,
Message message) Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException,
SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
CannotEstablishOmemoSessionException CannotEstablishOmemoSessionException
@ -871,9 +827,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws UndecidedOmemoIdentityException * @throws UndecidedOmemoIdentityException
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
*/ */
OmemoVAxolotlElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard, OmemoElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
ArrayList<BareJid> recipients, ArrayList<BareJid> recipients,
Message message) Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException,
SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
CannotEstablishOmemoSessionException CannotEstablishOmemoSessionException
@ -1042,9 +998,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* *
* @return OmemoMessageElement * @return OmemoMessageElement
*/ */
OmemoVAxolotlElement encryptOmemoMessage(OmemoManager.LoggedInOmemoManager managerGuard, OmemoElement encryptOmemoMessage(OmemoManager.LoggedInOmemoManager managerGuard,
HashMap<BareJid, ArrayList<OmemoDevice>> recipients, HashMap<BareJid, ArrayList<OmemoDevice>> recipients,
Message message) Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException throws CryptoFailedException, UndecidedOmemoIdentityException
{ {
OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>
@ -1095,8 +1051,8 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws CorruptedOmemoKeyException * @throws CorruptedOmemoKeyException
* @throws CannotEstablishOmemoSessionException * @throws CannotEstablishOmemoSessionException
*/ */
OmemoVAxolotlElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard, OmemoElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
OmemoDevice... recipients) OmemoDevice... recipients)
throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException, throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException,
CannotEstablishOmemoSessionException CannotEstablishOmemoSessionException
{ {
@ -1130,10 +1086,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws CorruptedOmemoKeyException * @throws CorruptedOmemoKeyException
* @throws CannotEstablishOmemoSessionException * @throws CannotEstablishOmemoSessionException
*/ */
OmemoVAxolotlElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard, OmemoElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
byte[] aesKey, byte[] aesKey,
byte[] iv, byte[] iv,
OmemoDevice... recipients) OmemoDevice... recipients)
throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException, throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException,
CannotEstablishOmemoSessionException CannotEstablishOmemoSessionException
{ {
@ -1177,7 +1133,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
buildSessionWithDevice(managerGuard, recipient, true); buildSessionWithDevice(managerGuard, recipient, true);
} }
OmemoVAxolotlElement keyTransportElement = prepareOmemoKeyTransportElement(managerGuard, recipient); OmemoElement keyTransportElement = prepareOmemoKeyTransportElement(managerGuard, recipient);
Message ratchetUpdateMessage = managerGuard.get().finishMessage(keyTransportElement); Message ratchetUpdateMessage = managerGuard.get().finishMessage(keyTransportElement);
ratchetUpdateMessage.setTo(recipient.getJid()); ratchetUpdateMessage.setTo(recipient.getJid());
@ -1262,7 +1218,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
*/ */
private static OmemoDevice getSender(OmemoManager.LoggedInOmemoManager managerGuard, private static OmemoDevice getSender(OmemoManager.LoggedInOmemoManager managerGuard,
Stanza stanza) { Stanza stanza) {
OmemoElement omemoElement = stanza.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL); OmemoElement omemoElement = stanza.getExtension(OmemoElement.NAME_ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
Jid sender = stanza.getFrom(); Jid sender = stanza.getFrom();
if (isMucMessage(managerGuard, stanza)) { if (isMucMessage(managerGuard, stanza)) {
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(managerGuard.get().getConnection()); MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(managerGuard.get().getConnection());
@ -1292,7 +1248,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
public void onOmemoMessageStanzaReceived(Stanza stanza, OmemoManager.LoggedInOmemoManager managerGuard) { public void onOmemoMessageStanzaReceived(Stanza stanza, OmemoManager.LoggedInOmemoManager managerGuard) {
OmemoManager omemoManager = managerGuard.get(); OmemoManager omemoManager = managerGuard.get();
Message decrypted; Message decrypted;
OmemoElement omemoMessage = stanza.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL); OmemoElement omemoMessage = stanza.getExtension(OmemoElement.NAME_ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
OmemoMessageInformation messageInfo = new OmemoMessageInformation(); OmemoMessageInformation messageInfo = new OmemoMessageInformation();
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection()); MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
OmemoDevice senderDevice = getSender(managerGuard, stanza); OmemoDevice senderDevice = getSender(managerGuard, stanza);
@ -1372,7 +1328,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
final OmemoDevice senderDevice = getSender(managerGuard, carbonCopy); final OmemoDevice senderDevice = getSender(managerGuard, carbonCopy);
Message decrypted; Message decrypted;
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection()); MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
OmemoElement omemoMessage = carbonCopy.getExtension(OmemoElement.ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL); OmemoElement omemoMessage = carbonCopy.getExtension(OmemoElement.NAME_ENCRYPTED, OMEMO_NAMESPACE_V_AXOLOTL);
OmemoMessageInformation messageInfo = new OmemoMessageInformation(); OmemoMessageInformation messageInfo = new OmemoMessageInformation();
if (CarbonExtension.Direction.received.equals(direction)) { if (CarbonExtension.Direction.received.equals(direction)) {

View file

@ -16,7 +16,7 @@
*/ */
package org.jivesoftware.smackx.omemo; package org.jivesoftware.smackx.omemo;
import static org.jivesoftware.smackx.omemo.util.OmemoConstants.TARGET_PRE_KEY_COUNT; import static org.jivesoftware.smackx.omemo.util.OmemoConstants.PRE_KEY_COUNT_PER_BUNDLE;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -26,7 +26,7 @@ import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
@ -99,7 +99,7 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
* @param contact Contact we received the list from. * @param contact Contact we received the list from.
* @param list List we received. * @param list List we received.
*/ */
void mergeCachedDeviceList(OmemoDevice userDevice, BareJid contact, OmemoDeviceListElement list) { CachedDeviceList mergeCachedDeviceList(OmemoDevice userDevice, BareJid contact, OmemoDeviceListElement list) {
CachedDeviceList cached = loadCachedDeviceList(userDevice, contact); CachedDeviceList cached = loadCachedDeviceList(userDevice, contact);
if (cached == null) { if (cached == null) {
@ -108,8 +108,10 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
if (list != null) { if (list != null) {
cached.merge(list.getDeviceIds()); cached.merge(list.getDeviceIds());
storeCachedDeviceList(userDevice, contact, cached);
} }
storeCachedDeviceList(userDevice, contact, cached);
return cached;
} }
/** /**
@ -165,13 +167,30 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
/** /**
* Pack a OmemoBundleElement containing our key material. * Pack a OmemoBundleElement containing our key material.
* If we used up n preKeys since we last published our bundle, generate n new preKeys and add them to the bundle. * If we used up n preKeys since we last published our bundle, generate n new preKeys and add them to the bundle.
* We should always publish TARGET_PRE_KEY_COUNT keys. * We should always publish PRE_KEY_COUNT_PER_BUNDLE keys.
* *
* @param userDevice our OmemoDevice. * @param userDevice our OmemoDevice.
* @return OmemoBundleElement * @return OmemoBundleElement
* @throws CorruptedOmemoKeyException when a key could not be loaded * @throws CorruptedOmemoKeyException when a key could not be loaded
*/ */
OmemoBundleVAxolotlElement packOmemoBundle(OmemoDevice userDevice) OmemoBundleElement_VAxolotl packOmemoBundle(OmemoDevice userDevice)
throws CorruptedOmemoKeyException
{
createMissingKeys(userDevice);
int currentSignedPreKeyId = loadCurrentOmemoSignedPreKeyId(userDevice);
T_SigPreKey currentSignedPreKey = loadOmemoSignedPreKeys(userDevice).get(currentSignedPreKeyId);
return new OmemoBundleElement_VAxolotl(
currentSignedPreKeyId,
keyUtil().signedPreKeyPublicForBundle(currentSignedPreKey),
keyUtil().signedPreKeySignatureFromKey(currentSignedPreKey),
keyUtil().identityKeyForBundle(keyUtil().identityKeyFromPair(loadOmemoIdentityKeyPair(userDevice))),
keyUtil().preKeyPublicKeysForBundle(loadOmemoPreKeys(userDevice))
);
}
private void createMissingKeys(OmemoDevice userDevice)
throws CorruptedOmemoKeyException throws CorruptedOmemoKeyException
{ {
T_IdKeyPair identityKeyPair = loadOmemoIdentityKeyPair(userDevice); T_IdKeyPair identityKeyPair = loadOmemoIdentityKeyPair(userDevice);
@ -183,29 +202,16 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
TreeMap<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(userDevice); TreeMap<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(userDevice);
if (signedPreKeys.size() == 0) { if (signedPreKeys.size() == 0) {
changeSignedPreKey(userDevice); changeSignedPreKey(userDevice);
signedPreKeys = loadOmemoSignedPreKeys(userDevice);
} }
int currentSignedPreKeyId = signedPreKeys.lastKey();
T_SigPreKey currentSignedPreKey = signedPreKeys.get(currentSignedPreKeyId);
TreeMap<Integer, T_PreKey> preKeys = loadOmemoPreKeys(userDevice); TreeMap<Integer, T_PreKey> preKeys = loadOmemoPreKeys(userDevice);
int newKeysCount = TARGET_PRE_KEY_COUNT - preKeys.size(); int newKeysCount = PRE_KEY_COUNT_PER_BUNDLE - preKeys.size();
int startId = preKeys.size() == 0 ? 0 : preKeys.lastKey(); int startId = preKeys.size() == 0 ? 0 : preKeys.lastKey();
if (newKeysCount > 0) { if (newKeysCount > 0) {
TreeMap<Integer, T_PreKey> newKeys = generateOmemoPreKeys(startId + 1, newKeysCount); TreeMap<Integer, T_PreKey> newKeys = generateOmemoPreKeys(startId + 1, newKeysCount);
storeOmemoPreKeys(userDevice, newKeys); storeOmemoPreKeys(userDevice, newKeys);
preKeys.putAll(newKeys);
} }
return new OmemoBundleVAxolotlElement(
currentSignedPreKeyId,
keyUtil().signedPreKeyPublicForBundle(currentSignedPreKey),
keyUtil().signedPreKeySignatureFromKey(currentSignedPreKey),
keyUtil().identityKeyForBundle(keyUtil().identityKeyFromPair(identityKeyPair)),
keyUtil().preKeyPublicKeysForBundle(preKeys)
);
} }
// *sigh* // *sigh*
@ -374,6 +380,10 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
*/ */
public abstract T_SigPreKey loadOmemoSignedPreKey(OmemoDevice userDevice, int signedPreKeyId); public abstract T_SigPreKey loadOmemoSignedPreKey(OmemoDevice userDevice, int signedPreKeyId);
public int loadCurrentOmemoSignedPreKeyId(OmemoDevice userDevice) {
return loadOmemoSignedPreKeys(userDevice).lastKey();
}
/** /**
* Load all our signed PreKeys. * Load all our signed PreKeys.
* *
@ -475,6 +485,15 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
*/ */
public abstract CachedDeviceList loadCachedDeviceList(OmemoDevice userDevice, BareJid contact); public abstract CachedDeviceList loadCachedDeviceList(OmemoDevice userDevice, BareJid contact);
/**
* Load a list of deviceIds from our own devices.
* @param userDevice
* @return
*/
public CachedDeviceList loadCachedDeviceList(OmemoDevice userDevice) {
return loadCachedDeviceList(userDevice, userDevice.getJid());
}
/** /**
* Store the DeviceList of the contact in local storage. * Store the DeviceList of the contact in local storage.
* See this as a cache. * See this as a cache.

View file

@ -16,12 +16,15 @@
*/ */
package org.jivesoftware.smackx.omemo.element; package org.jivesoftware.smackx.omemo.element;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/** /**
* Class that represents an OMEMO Bundle element. * Class that represents an OMEMO Bundle element.
* TODO: Move functionality to here.
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
@ -36,8 +39,173 @@ public abstract class OmemoBundleElement implements ExtensionElement {
public static final String PRE_KEY_PUB = "preKeyPublic"; public static final String PRE_KEY_PUB = "preKeyPublic";
public static final String PRE_KEY_ID = "preKeyId"; public static final String PRE_KEY_ID = "preKeyId";
private final int signedPreKeyId;
private final String signedPreKeyB64;
private byte[] signedPreKey;
private final String signedPreKeySignatureB64;
private byte[] signedPreKeySignature;
private final String identityKeyB64;
private byte[] identityKey;
private final HashMap<Integer, String> preKeysB64;
private HashMap<Integer, byte[]> preKeys;
/**
* Constructor to create a Bundle Element from base64 Strings.
*
* @param signedPreKeyId id
* @param signedPreKeyB64 base64 encoded signedPreKey
* @param signedPreKeySigB64 base64 encoded signedPreKeySignature
* @param identityKeyB64 base64 encoded identityKey
* @param preKeysB64 HashMap of base64 encoded preKeys
*/
public OmemoBundleElement(int signedPreKeyId, String signedPreKeyB64, String signedPreKeySigB64, String identityKeyB64, HashMap<Integer, String> preKeysB64) {
this.signedPreKeyId = signedPreKeyId;
this.signedPreKeyB64 = signedPreKeyB64;
this.signedPreKeySignatureB64 = signedPreKeySigB64;
this.identityKeyB64 = identityKeyB64;
this.preKeysB64 = preKeysB64;
}
/**
* Constructor to create a Bundle Element from decoded byte arrays.
*
* @param signedPreKeyId id
* @param signedPreKey signedPreKey
* @param signedPreKeySig signedPreKeySignature
* @param identityKey identityKey
* @param preKeys HashMap of preKeys
*/
public OmemoBundleElement(int signedPreKeyId, byte[] signedPreKey, byte[] signedPreKeySig, byte[] identityKey, HashMap<Integer, byte[]> preKeys) {
this.signedPreKeyId = signedPreKeyId;
this.signedPreKey = signedPreKey;
this.signedPreKeyB64 = Base64.encodeToString(signedPreKey);
this.signedPreKeySignature = signedPreKeySig;
this.signedPreKeySignatureB64 = Base64.encodeToString(signedPreKeySignature);
this.identityKey = identityKey;
this.identityKeyB64 = Base64.encodeToString(identityKey);
this.preKeys = preKeys;
this.preKeysB64 = new HashMap<>();
for (int id : preKeys.keySet()) {
preKeysB64.put(id, Base64.encodeToString(preKeys.get(id)));
}
}
/**
* Return the signedPreKey of the OmemoBundleElement.
*
* @return signedPreKey as byte array
*/
public byte[] getSignedPreKey() {
if (signedPreKey == null) {
signedPreKey = Base64.decode(signedPreKeyB64);
}
return this.signedPreKey.clone();
}
/**
* Return the id of the signedPreKey in the bundle.
*
* @return id of signedPreKey
*/
public int getSignedPreKeyId() {
return this.signedPreKeyId;
}
/**
* Get the signature of the signedPreKey.
*
* @return signature as byte array
*/
public byte[] getSignedPreKeySignature() {
if (signedPreKeySignature == null) {
signedPreKeySignature = Base64.decode(signedPreKeySignatureB64);
}
return signedPreKeySignature.clone();
}
/**
* Return the public identityKey of the bundles owner.
* This can be used to check the signedPreKeys signature.
* The fingerprint of this key is, what the user has to verify.
*
* @return public identityKey as byte array
*/
public byte[] getIdentityKey() {
if (identityKey == null) {
identityKey = Base64.decode(identityKeyB64);
}
return this.identityKey.clone();
}
/**
* Return the HashMap of preKeys in the bundle.
* The map uses the preKeys ids as key and the preKeys as value.
*
* @return preKeys
*/
public HashMap<Integer, byte[]> getPreKeys() {
if (preKeys == null) {
preKeys = new HashMap<>();
for (int id : preKeysB64.keySet()) {
preKeys.put(id, Base64.decode(preKeysB64.get(id)));
}
}
return this.preKeys;
}
/**
* Return a single preKey from the map.
*
* @param id id of the preKey
* @return the preKey
*/
public byte[] getPreKey(int id) {
return getPreKeys().get(id);
}
@Override @Override
public abstract XmlStringBuilder toXML(String enclosingNamespace); public String getElementName() {
return BUNDLE;
}
@Override
public XmlStringBuilder toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this, enclosingNamespace).rightAngleBracket();
sb.halfOpenElement(SIGNED_PRE_KEY_PUB).attribute(SIGNED_PRE_KEY_ID, signedPreKeyId).rightAngleBracket()
.append(signedPreKeyB64).closeElement(SIGNED_PRE_KEY_PUB);
sb.openElement(SIGNED_PRE_KEY_SIG).append(signedPreKeySignatureB64).closeElement(SIGNED_PRE_KEY_SIG);
sb.openElement(IDENTITY_KEY).append(identityKeyB64).closeElement(IDENTITY_KEY);
sb.openElement(PRE_KEYS);
for (Map.Entry<Integer, String> p : this.preKeysB64.entrySet()) {
sb.halfOpenElement(PRE_KEY_PUB).attribute(PRE_KEY_ID, p.getKey()).rightAngleBracket()
.append(p.getValue()).closeElement(PRE_KEY_PUB);
}
sb.closeElement(PRE_KEYS);
sb.closeElement(this);
return sb;
}
@Override
public String toString() {
String out = "OmemoBundleElement[\n";
out += SIGNED_PRE_KEY_PUB + " " + SIGNED_PRE_KEY_ID + "=" + signedPreKeyId + ": " + signedPreKeyB64 + "\n";
out += SIGNED_PRE_KEY_SIG + ": " + signedPreKeySignatureB64 + "\n";
out += IDENTITY_KEY + ": " + identityKeyB64 + "\n";
out += PRE_KEYS + " (" + preKeysB64.size() + ")\n";
for (Map.Entry<Integer, String> e : preKeysB64.entrySet()) {
out += PRE_KEY_PUB + " " + PRE_KEY_ID + "=" + e.getKey() + ": " + e.getValue() + "\n";
}
return out;
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {

View file

@ -0,0 +1,43 @@
/**
*
* 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 static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
import java.util.HashMap;
/**
* OMEMO device bundle as described here:
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing (Example 3).
*
* @author Paul Schaub
*/
public class OmemoBundleElement_VAxolotl extends OmemoBundleElement {
public OmemoBundleElement_VAxolotl(int signedPreKeyId, String signedPreKeyB64, String signedPreKeySigB64, String identityKeyB64, HashMap<Integer, String> preKeysB64) {
super(signedPreKeyId, signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64);
}
public OmemoBundleElement_VAxolotl(int signedPreKeyId, byte[] signedPreKey, byte[] signedPreKeySig, byte[] identityKey, HashMap<Integer, byte[]> preKeys) {
super(signedPreKeyId, signedPreKey, signedPreKeySig, identityKey, preKeys);
}
@Override
public String getNamespace() {
return OMEMO_NAMESPACE_V_AXOLOTL;
}
}

View file

@ -1,207 +0,0 @@
/**
*
* 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 static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* OMEMO device bundle as described here:
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing (Example 3).
*
* @author Paul Schaub
*/
public class OmemoBundleVAxolotlElement extends OmemoBundleElement {
private final int signedPreKeyId;
private final String signedPreKeyB64;
private byte[] signedPreKey;
private final String signedPreKeySignatureB64;
private byte[] signedPreKeySignature;
private final String identityKeyB64;
private byte[] identityKey;
private final HashMap<Integer, String> preKeysB64;
private HashMap<Integer, byte[]> preKeys;
/**
* Constructor to create a Bundle Element from base64 Strings.
*
* @param signedPreKeyId id
* @param signedPreKeyB64 base64 encoded signedPreKey
* @param signedPreKeySigB64 base64 encoded signedPreKeySignature
* @param identityKeyB64 base64 encoded identityKey
* @param preKeysB64 HashMap of base64 encoded preKeys
*/
public OmemoBundleVAxolotlElement(int signedPreKeyId, String signedPreKeyB64, String signedPreKeySigB64, String identityKeyB64, HashMap<Integer, String> preKeysB64) {
this.signedPreKeyId = signedPreKeyId;
this.signedPreKeyB64 = signedPreKeyB64;
this.signedPreKeySignatureB64 = signedPreKeySigB64;
this.identityKeyB64 = identityKeyB64;
this.preKeysB64 = preKeysB64;
}
/**
* Constructor to create a Bundle Element from decoded byte arrays.
*
* @param signedPreKeyId id
* @param signedPreKey signedPreKey
* @param signedPreKeySig signedPreKeySignature
* @param identityKey identityKey
* @param preKeys HashMap of preKeys
*/
public OmemoBundleVAxolotlElement(int signedPreKeyId, byte[] signedPreKey, byte[] signedPreKeySig, byte[] identityKey, HashMap<Integer, byte[]> preKeys) {
this.signedPreKeyId = signedPreKeyId;
this.signedPreKey = signedPreKey;
this.signedPreKeyB64 = Base64.encodeToString(signedPreKey);
this.signedPreKeySignature = signedPreKeySig;
this.signedPreKeySignatureB64 = Base64.encodeToString(signedPreKeySignature);
this.identityKey = identityKey;
this.identityKeyB64 = Base64.encodeToString(identityKey);
this.preKeys = preKeys;
this.preKeysB64 = new HashMap<>();
for (int id : preKeys.keySet()) {
preKeysB64.put(id, Base64.encodeToString(preKeys.get(id)));
}
}
/**
* Return the signedPreKey of the OmemoBundleElement.
*
* @return signedPreKey as byte array
*/
public byte[] getSignedPreKey() {
if (signedPreKey == null) {
signedPreKey = Base64.decode(signedPreKeyB64);
}
return this.signedPreKey.clone();
}
/**
* Return the id of the signedPreKey in the bundle.
*
* @return id of signedPreKey
*/
public int getSignedPreKeyId() {
return this.signedPreKeyId;
}
/**
* Get the signature of the signedPreKey.
*
* @return signature as byte array
*/
public byte[] getSignedPreKeySignature() {
if (signedPreKeySignature == null) {
signedPreKeySignature = Base64.decode(signedPreKeySignatureB64);
}
return signedPreKeySignature.clone();
}
/**
* Return the public identityKey of the bundles owner.
* This can be used to check the signedPreKeys signature.
* The fingerprint of this key is, what the user has to verify.
*
* @return public identityKey as byte array
*/
public byte[] getIdentityKey() {
if (identityKey == null) {
identityKey = Base64.decode(identityKeyB64);
}
return this.identityKey.clone();
}
/**
* Return the HashMap of preKeys in the bundle.
* The map uses the preKeys ids as key and the preKeys as value.
*
* @return preKeys
*/
public HashMap<Integer, byte[]> getPreKeys() {
if (preKeys == null) {
preKeys = new HashMap<>();
for (int id : preKeysB64.keySet()) {
preKeys.put(id, Base64.decode(preKeysB64.get(id)));
}
}
return this.preKeys;
}
/**
* Return a single preKey from the map.
*
* @param id id of the preKey
* @return the preKey
*/
public byte[] getPreKey(int id) {
return getPreKeys().get(id);
}
@Override
public String getElementName() {
return BUNDLE;
}
@Override
public XmlStringBuilder toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this).rightAngleBracket();
sb.halfOpenElement(SIGNED_PRE_KEY_PUB).attribute(SIGNED_PRE_KEY_ID, signedPreKeyId).rightAngleBracket()
.append(signedPreKeyB64).closeElement(SIGNED_PRE_KEY_PUB);
sb.openElement(SIGNED_PRE_KEY_SIG).append(signedPreKeySignatureB64).closeElement(SIGNED_PRE_KEY_SIG);
sb.openElement(IDENTITY_KEY).append(identityKeyB64).closeElement(IDENTITY_KEY);
sb.openElement(PRE_KEYS);
for (Map.Entry<Integer, String> p : this.preKeysB64.entrySet()) {
sb.halfOpenElement(PRE_KEY_PUB).attribute(PRE_KEY_ID, p.getKey()).rightAngleBracket()
.append(p.getValue()).closeElement(PRE_KEY_PUB);
}
sb.closeElement(PRE_KEYS);
sb.closeElement(this);
return sb;
}
@Override
public String getNamespace() {
return OMEMO_NAMESPACE_V_AXOLOTL;
}
@Override
public String toString() {
String out = "OmemoBundleElement[\n";
out += SIGNED_PRE_KEY_PUB + " " + SIGNED_PRE_KEY_ID + "=" + signedPreKeyId + ": " + signedPreKeyB64 + "\n";
out += SIGNED_PRE_KEY_SIG + ": " + signedPreKeySignatureB64 + "\n";
out += IDENTITY_KEY + ": " + identityKeyB64 + "\n";
out += PRE_KEYS + " (" + preKeysB64.size() + ")\n";
for (Map.Entry<Integer, String> e : preKeysB64.entrySet()) {
out += PRE_KEY_PUB + " " + PRE_KEY_ID + "=" + e.getKey() + ": " + e.getValue() + "\n";
}
return out;
}
}

View file

@ -25,9 +25,9 @@ import java.util.Set;
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
public class OmemoDeviceListVAxolotlElement extends OmemoDeviceListElement { public class OmemoDeviceListElement_VAxolotl extends OmemoDeviceListElement {
public OmemoDeviceListVAxolotlElement(Set<Integer> deviceIds) { public OmemoDeviceListElement_VAxolotl(Set<Integer> deviceIds) {
super(deviceIds); super(deviceIds);
} }

View file

@ -16,17 +16,13 @@
*/ */
package org.jivesoftware.smackx.omemo.element; package org.jivesoftware.smackx.omemo.element;
import java.util.ArrayList;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.util.stringencoder.Base64;
/** /**
* Class that represents an OmemoElement. * Class that represents an OmemoElement.
* TODO: Move functionality here.
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
@ -35,17 +31,11 @@ public abstract class OmemoElement implements ExtensionElement {
public static final int TYPE_OMEMO_PREKEY_MESSAGE = 1; public static final int TYPE_OMEMO_PREKEY_MESSAGE = 1;
public static final int TYPE_OMEMO_MESSAGE = 0; public static final int TYPE_OMEMO_MESSAGE = 0;
public static final String ENCRYPTED = "encrypted"; public static final String NAME_ENCRYPTED = "encrypted";
public static final String HEADER = "header"; public static final String ATTR_PAYLOAD = "payload";
public static final String SID = "sid";
public static final String KEY = "key";
public static final String RID = "rid";
public static final String PREKEY = "prekey";
public static final String IV = "iv";
public static final String PAYLOAD = "payload";
protected final OmemoElement.OmemoHeader header; private final OmemoHeaderElement header;
protected final byte[] payload; private final byte[] payload;
/** /**
* Create a new OmemoMessageElement from a header and a payload. * Create a new OmemoMessageElement from a header and a payload.
@ -53,12 +43,12 @@ public abstract class OmemoElement implements ExtensionElement {
* @param header header of the message * @param header header of the message
* @param payload payload * @param payload payload
*/ */
public OmemoElement(OmemoElement.OmemoHeader header, byte[] payload) { public OmemoElement(OmemoHeaderElement header, byte[] payload) {
this.header = Objects.requireNonNull(header); this.header = Objects.requireNonNull(header);
this.payload = payload; this.payload = payload;
} }
public OmemoElement.OmemoHeader getHeader() { public OmemoHeaderElement getHeader() {
return header; return header;
} }
@ -82,113 +72,22 @@ public abstract class OmemoElement implements ExtensionElement {
return payload != null; return payload != null;
} }
/** @Override
* Header element of the message. The header contains information about the sender and the encrypted keys for public XmlStringBuilder toXML(String enclosingNamespace) {
* the recipients, as well as the iv element for AES. XmlStringBuilder sb = new XmlStringBuilder(this, enclosingNamespace).rightAngleBracket();
*/
public static class OmemoHeader implements NamedElement {
private final int sid;
private final ArrayList<Key> keys;
private final byte[] iv;
public OmemoHeader(int sid, ArrayList<OmemoHeader.Key> keys, byte[] iv) { sb.element(header);
this.sid = sid;
this.keys = keys; if (payload != null) {
this.iv = iv; sb.openElement(ATTR_PAYLOAD).append(Base64.encodeToString(payload)).closeElement(ATTR_PAYLOAD);
} }
/** sb.closeElement(this);
* Return the deviceId of the sender of the message. return sb;
* }
* @return senders id
*/
public int getSid() {
return sid;
}
public ArrayList<OmemoHeader.Key> getKeys() { @Override
return new ArrayList<>(keys); public String getElementName() {
} return NAME_ENCRYPTED;
public byte[] getIv() {
return iv != null ? iv.clone() : null;
}
@Override
public String getElementName() {
return HEADER;
}
@Override
public CharSequence toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this);
sb.attribute(SID, getSid()).rightAngleBracket();
for (OmemoHeader.Key k : getKeys()) {
sb.element(k);
}
sb.openElement(IV).append(Base64.encodeToString(getIv())).closeElement(IV);
return sb.closeElement(this);
}
/**
* Small class to collect key (byte[]), its id and whether its a prekey or not.
*/
public static class Key implements NamedElement {
final byte[] data;
final int id;
final boolean preKey;
public Key(byte[] data, int id) {
this.data = data;
this.id = id;
this.preKey = false;
}
public Key(byte[] data, int id, boolean preKey) {
this.data = data;
this.id = id;
this.preKey = preKey;
}
public int getId() {
return this.id;
}
public byte[] getData() {
return this.data;
}
public boolean isPreKey() {
return this.preKey;
}
@Override
public String toString() {
return Integer.toString(id);
}
@Override
public String getElementName() {
return KEY;
}
@Override
public CharSequence toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this);
if (isPreKey()) {
sb.attribute(PREKEY, true);
}
sb.attribute(RID, getId());
sb.rightAngleBracket();
sb.append(Base64.encodeToString(getData()));
sb.closeElement(this);
return sb;
}
}
} }
} }

View file

@ -0,0 +1,42 @@
/**
*
* 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 static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
/**
* An OMEMO (PreKey)WhisperMessage element.
*
* @author Paul Schaub
*/
public class OmemoElement_VAxolotl extends OmemoElement {
/**
* Create a new OmemoMessageElement from a header and a payload.
*
* @param header header of the message
* @param payload payload
*/
public OmemoElement_VAxolotl(OmemoHeaderElement_VAxolotl header, byte[] payload) {
super(header, payload);
}
@Override
public String getNamespace() {
return OMEMO_NAMESPACE_V_AXOLOTL;
}
}

View file

@ -0,0 +1,82 @@
/**
*
* 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 java.util.ArrayList;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* Header element of the message. The header contains information about the sender and the encrypted keys for
* the recipients, as well as the iv element for AES.
*/
public abstract class OmemoHeaderElement implements NamedElement {
public static final String NAME_HEADER = "header";
public static final String ATTR_SID = "sid";
public static final String ATTR_IV = "iv";
private final int sid;
private final ArrayList<OmemoKeyElement> keys;
private final byte[] iv;
public OmemoHeaderElement(int sid, ArrayList<OmemoKeyElement> keys, byte[] iv) {
this.sid = sid;
this.keys = keys;
this.iv = iv;
}
/**
* Return the deviceId of the sender of the message.
*
* @return senders id
*/
public int getSid() {
return sid;
}
public ArrayList<OmemoKeyElement> getKeys() {
return new ArrayList<>(keys);
}
public byte[] getIv() {
return iv != null ? iv.clone() : null;
}
@Override
public String getElementName() {
return NAME_HEADER;
}
@Override
public CharSequence toXML() {
XmlStringBuilder sb = new XmlStringBuilder(this);
sb.attribute(ATTR_SID, getSid()).rightAngleBracket();
for (OmemoKeyElement k : getKeys()) {
sb.element(k);
}
sb.openElement(ATTR_IV).append(Base64.encodeToString(getIv())).closeElement(ATTR_IV);
return sb.closeElement(this);
}
}

View file

@ -0,0 +1,27 @@
/**
*
* 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 java.util.ArrayList;
public class OmemoHeaderElement_VAxolotl extends OmemoHeaderElement {
public OmemoHeaderElement_VAxolotl(int sid, ArrayList<OmemoKeyElement> keys, byte[] iv) {
super(sid, keys, iv);
}
}

View file

@ -0,0 +1,68 @@
package org.jivesoftware.smackx.omemo.element;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* Small class to collect key (byte[]), its id and whether its a preKey or not.
*/
public class OmemoKeyElement implements NamedElement {
public static final String NAME_KEY = "key";
public static final String ATTR_RID = "rid";
public static final String ATTR_PREKEY = "prekey";
private final byte[] data;
private final int id;
private final boolean preKey;
public OmemoKeyElement(byte[] data, int id) {
this.data = data;
this.id = id;
this.preKey = false;
}
public OmemoKeyElement(byte[] data, int id, boolean preKey) {
this.data = data;
this.id = id;
this.preKey = preKey;
}
public int getId() {
return this.id;
}
public byte[] getData() {
return this.data;
}
public boolean isPreKey() {
return this.preKey;
}
@Override
public String toString() {
return Integer.toString(id);
}
@Override
public String getElementName() {
return NAME_KEY;
}
@Override
public CharSequence toXML() {
XmlStringBuilder sb = new XmlStringBuilder(this);
if (isPreKey()) {
sb.attribute(ATTR_PREKEY, true);
}
sb.attribute(ATTR_RID, getId());
sb.rightAngleBracket();
sb.append(Base64.encodeToString(getData()));
sb.closeElement(this);
return sb;
}
}

View file

@ -1,86 +0,0 @@
/**
*
* 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 static org.jivesoftware.smackx.omemo.util.OmemoConstants.OMEMO_NAMESPACE_V_AXOLOTL;
import java.io.UnsupportedEncodingException;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* An OMEMO (PreKey)WhisperMessage element.
*
* @author Paul Schaub
*/
public class OmemoVAxolotlElement extends OmemoElement {
/**
* Create a new OmemoMessageElement from a header and a payload.
*
* @param header header of the message
* @param payload payload
*/
public OmemoVAxolotlElement(OmemoHeader header, byte[] payload) {
super(header, payload);
}
@Override
public String getElementName() {
return ENCRYPTED;
}
@Override
public XmlStringBuilder toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this).rightAngleBracket();
sb.element(header);
if (payload != null) {
sb.openElement(PAYLOAD).append(Base64.encodeToString(payload)).closeElement(PAYLOAD);
}
sb.closeElement(this);
return sb;
}
@Override
public String getNamespace() {
return OMEMO_NAMESPACE_V_AXOLOTL;
}
@Override
public String toString() {
try {
StringBuilder s = new StringBuilder("Encrypted:\n")
.append(" header: sid: ").append(getHeader().getSid()).append('\n');
for (OmemoHeader.Key k : getHeader().getKeys()) {
s.append(" key: prekey: ").append(k.isPreKey()).append(" rid: ")
.append(k.getId()).append(' ')
.append(new String(k.getData(), StringUtils.UTF8)).append('\n');
}
s.append(" iv: ").append(new String(getHeader().getIv(), StringUtils.UTF8)).append('\n');
s.append(" payload: ").append(new String(getPayload(), StringUtils.UTF8));
return s.toString();
} catch (UnsupportedEncodingException e) {
// UTF-8 must be supported on all platforms claiming to be java compatible.
throw new AssertionError(e);
}
}
}

View file

@ -35,6 +35,10 @@ public class CannotEstablishOmemoSessionException extends Exception {
private final HashMap<BareJid, HashMap<OmemoDevice, Throwable>> failures = new HashMap<>(); private final HashMap<BareJid, HashMap<OmemoDevice, Throwable>> failures = new HashMap<>();
private final HashMap<BareJid, ArrayList<OmemoDevice>> successes = new HashMap<>(); private final HashMap<BareJid, ArrayList<OmemoDevice>> successes = new HashMap<>();
public CannotEstablishOmemoSessionException() {
super();
}
public CannotEstablishOmemoSessionException(OmemoDevice failed, Throwable reason) { public CannotEstablishOmemoSessionException(OmemoDevice failed, Throwable reason) {
super(); super();
getFailsOfContact(failed.getJid()).put(failed, reason); getFailsOfContact(failed.getJid()).put(failed, reason);

View file

@ -100,12 +100,13 @@ public class CachedDeviceList implements Serializable {
} }
/** /**
* Add a device to the list of active devices. * Add a device to the list of active devices and remove it from inactive.
* *
* @param deviceId deviceId that will be added * @param deviceId deviceId that will be added
*/ */
public void addDevice(int deviceId) { public void addDevice(int deviceId) {
activeDevices.add(deviceId); activeDevices.add(deviceId);
inactiveDevices.remove(deviceId);
} }
/** /**
@ -118,6 +119,10 @@ public class CachedDeviceList implements Serializable {
return activeDevices.contains(deviceId) || inactiveDevices.contains(deviceId); return activeDevices.contains(deviceId) || inactiveDevices.contains(deviceId);
} }
public boolean isActive(int deviceId) {
return getActiveDevices().contains(deviceId);
}
@Override @Override
public String toString() { public String toString() {
String out = "active: ["; String out = "active: [";

View file

@ -31,7 +31,7 @@ import java.util.HashMap;
import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement_VAxolotl;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -40,9 +40,9 @@ import org.xmlpull.v1.XmlPullParser;
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoBundleVAxolotlElement> { public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoBundleElement_VAxolotl> {
@Override @Override
public OmemoBundleVAxolotlElement parse(XmlPullParser parser, int initialDepth) throws Exception { public OmemoBundleElement_VAxolotl parse(XmlPullParser parser, int initialDepth) throws Exception {
boolean stop = false; boolean stop = false;
boolean inPreKeys = false; boolean inPreKeys = false;
@ -96,6 +96,6 @@ public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoB
break; break;
} }
} }
return new OmemoBundleVAxolotlElement(signedPreKeyId, signedPreKey, signedPreKeySignature, identityKey, preKeys); return new OmemoBundleElement_VAxolotl(signedPreKeyId, signedPreKey, signedPreKeySignature, identityKey, preKeys);
} }
} }

View file

@ -27,7 +27,7 @@ import java.util.Set;
import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -36,10 +36,10 @@ import org.xmlpull.v1.XmlPullParser;
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<OmemoDeviceListVAxolotlElement> { public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<OmemoDeviceListElement_VAxolotl> {
@Override @Override
public OmemoDeviceListVAxolotlElement parse(XmlPullParser parser, int initialDepth) throws Exception { public OmemoDeviceListElement_VAxolotl parse(XmlPullParser parser, int initialDepth) throws Exception {
Set<Integer> deviceListIds = new HashSet<>(); Set<Integer> deviceListIds = new HashSet<>();
boolean stop = false; boolean stop = false;
while (!stop) { while (!stop) {
@ -63,6 +63,6 @@ public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<Om
break; break;
} }
} }
return new OmemoDeviceListVAxolotlElement(deviceListIds); return new OmemoDeviceListElement_VAxolotl(deviceListIds);
} }
} }

View file

@ -16,14 +16,8 @@
*/ */
package org.jivesoftware.smackx.omemo.provider; package org.jivesoftware.smackx.omemo.provider;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.ENCRYPTED; import static org.jivesoftware.smackx.omemo.element.OmemoElement.ATTR_PAYLOAD;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.HEADER; import static org.jivesoftware.smackx.omemo.element.OmemoElement.NAME_ENCRYPTED;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.IV;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.KEY;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.PAYLOAD;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.PREKEY;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.RID;
import static org.jivesoftware.smackx.omemo.element.OmemoElement.SID;
import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG;
@ -31,8 +25,10 @@ import java.util.ArrayList;
import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoHeaderElement;
import org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -41,13 +37,13 @@ import org.xmlpull.v1.XmlPullParser;
* *
* @author Paul Schaub * @author Paul Schaub
*/ */
public class OmemoVAxolotlProvider extends ExtensionElementProvider<OmemoVAxolotlElement> { public class OmemoVAxolotlProvider extends ExtensionElementProvider<OmemoElement_VAxolotl> {
@Override @Override
public OmemoVAxolotlElement parse(XmlPullParser parser, int initialDepth) throws Exception { public OmemoElement_VAxolotl parse(XmlPullParser parser, int initialDepth) throws Exception {
boolean inEncrypted = true; boolean inEncrypted = true;
int sid = -1; int sid = -1;
ArrayList<OmemoVAxolotlElement.OmemoHeader.Key> keys = new ArrayList<>(); ArrayList<OmemoKeyElement> keys = new ArrayList<>();
byte[] iv = null; byte[] iv = null;
byte[] payload = null; byte[] payload = null;
@ -57,41 +53,41 @@ public class OmemoVAxolotlProvider extends ExtensionElementProvider<OmemoVAxolot
switch (tag) { switch (tag) {
case START_TAG: case START_TAG:
switch (name) { switch (name) {
case HEADER: case OmemoHeaderElement.NAME_HEADER:
for (int i = 0; i < parser.getAttributeCount(); i++) { for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals(SID)) { if (parser.getAttributeName(i).equals(OmemoHeaderElement.ATTR_SID)) {
sid = Integer.parseInt(parser.getAttributeValue(i)); sid = Integer.parseInt(parser.getAttributeValue(i));
} }
} }
break; break;
case KEY: case OmemoKeyElement.NAME_KEY:
boolean prekey = false; boolean prekey = false;
int rid = -1; int rid = -1;
for (int i = 0; i < parser.getAttributeCount(); i++) { for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals(PREKEY)) { if (parser.getAttributeName(i).equals(OmemoKeyElement.ATTR_PREKEY)) {
prekey = Boolean.parseBoolean(parser.getAttributeValue(i)); prekey = Boolean.parseBoolean(parser.getAttributeValue(i));
} else if (parser.getAttributeName(i).equals(RID)) { } else if (parser.getAttributeName(i).equals(OmemoKeyElement.ATTR_RID)) {
rid = Integer.parseInt(parser.getAttributeValue(i)); rid = Integer.parseInt(parser.getAttributeValue(i));
} }
} }
keys.add(new OmemoVAxolotlElement.OmemoHeader.Key(Base64.decode(parser.nextText()), rid, prekey)); keys.add(new OmemoKeyElement(Base64.decode(parser.nextText()), rid, prekey));
break; break;
case IV: case OmemoHeaderElement.ATTR_IV:
iv = Base64.decode(parser.nextText()); iv = Base64.decode(parser.nextText());
break; break;
case PAYLOAD: case ATTR_PAYLOAD:
payload = Base64.decode(parser.nextText()); payload = Base64.decode(parser.nextText());
break; break;
} }
break; break;
case END_TAG: case END_TAG:
if (name.equals(ENCRYPTED)) { if (name.equals(NAME_ENCRYPTED)) {
inEncrypted = false; inEncrypted = false;
} }
break; break;
} }
} }
OmemoVAxolotlElement.OmemoHeader header = new OmemoVAxolotlElement.OmemoHeader(sid, keys, iv); OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(sid, keys, iv);
return new OmemoVAxolotlElement(header, payload); return new OmemoElement_VAxolotl(header, payload);
} }
} }

View file

@ -37,7 +37,7 @@ public final class OmemoConstants {
/** /**
* How many preKeys do we want to publish? * How many preKeys do we want to publish?
*/ */
public static final int TARGET_PRE_KEY_COUNT = 100; public static final int PRE_KEY_COUNT_PER_BUNDLE = 100;
/** /**
* Return the node name of the PEP node containing the device bundle of the device with device id deviceId. * Return the node name of the PEP node containing the device bundle of the device with device id deviceId.
@ -49,7 +49,7 @@ public final class OmemoConstants {
return PEP_NODE_BUNDLES + ":" + deviceId; return PEP_NODE_BUNDLES + ":" + deviceId;
} }
public static final String BODY_OMEMO_HINT = "I sent you an OMEMO encrypted message but your client doesnt seem to support that. Find more information on https://conversations.im/omemo"; public static final String BODY_OMEMO_HINT = "I sent you an OMEMO encrypted message but your client doesn't seem to support that. Find more information on https://conversations.im/omemo";
/** /**
* Information about the keys used for message encryption. * Information about the keys used for message encryption.

View file

@ -23,7 +23,7 @@ import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.internal.OmemoDevice; import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
@ -59,7 +59,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return identityKey * @return identityKey
* @throws CorruptedOmemoKeyException if the key is damaged/malformed * @throws CorruptedOmemoKeyException if the key is damaged/malformed
*/ */
public T_IdKey identityKey(OmemoBundleVAxolotlElement bundle) throws CorruptedOmemoKeyException { public T_IdKey identityKey(OmemoBundleElement bundle) throws CorruptedOmemoKeyException {
return identityKeyFromBytes(bundle.getIdentityKey()); return identityKeyFromBytes(bundle.getIdentityKey());
} }
@ -70,7 +70,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return singedPreKey * @return singedPreKey
* @throws CorruptedOmemoKeyException if the key is damaged/malformed * @throws CorruptedOmemoKeyException if the key is damaged/malformed
*/ */
public T_ECPub signedPreKeyPublic(OmemoBundleVAxolotlElement bundle) throws CorruptedOmemoKeyException { public T_ECPub signedPreKeyPublic(OmemoBundleElement bundle) throws CorruptedOmemoKeyException {
return signedPreKeyPublicFromBytes(bundle.getSignedPreKey()); return signedPreKeyPublicFromBytes(bundle.getSignedPreKey());
} }
@ -80,7 +80,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @param bundle OmemoBundleElement * @param bundle OmemoBundleElement
* @return signedPreKeyId * @return signedPreKeyId
*/ */
public int signedPreKeyId(OmemoBundleVAxolotlElement bundle) { public int signedPreKeyId(OmemoBundleElement bundle) {
return bundle.getSignedPreKeyId(); return bundle.getSignedPreKeyId();
} }
@ -90,7 +90,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @param bundle OmemoBundleElement * @param bundle OmemoBundleElement
* @return signature * @return signature
*/ */
public byte[] signedPreKeySignature(OmemoBundleVAxolotlElement bundle) { public byte[] signedPreKeySignature(OmemoBundleElement bundle) {
return bundle.getSignedPreKeySignature(); return bundle.getSignedPreKeySignature();
} }
@ -102,7 +102,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return the preKey * @return the preKey
* @throws CorruptedOmemoKeyException when the key cannot be parsed from bytes * @throws CorruptedOmemoKeyException when the key cannot be parsed from bytes
*/ */
public T_ECPub preKeyPublic(OmemoBundleVAxolotlElement bundle, int keyId) throws CorruptedOmemoKeyException { public T_ECPub preKeyPublic(OmemoBundleElement bundle, int keyId) throws CorruptedOmemoKeyException {
return preKeyPublicFromBytes(bundle.getPreKey(keyId)); return preKeyPublicFromBytes(bundle.getPreKey(keyId));
} }
@ -116,7 +116,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return a HashMap with one T_Bundle per preKey and the preKeyId as key * @return a HashMap with one T_Bundle per preKey and the preKeyId as key
* @throws CorruptedOmemoKeyException when one of the keys cannot be parsed * @throws CorruptedOmemoKeyException when one of the keys cannot be parsed
*/ */
public HashMap<Integer, T_Bundle> bundles(OmemoBundleVAxolotlElement bundle, OmemoDevice contact) throws CorruptedOmemoKeyException { public HashMap<Integer, T_Bundle> bundles(OmemoBundleElement bundle, OmemoDevice contact) throws CorruptedOmemoKeyException {
HashMap<Integer, T_Bundle> bundles = new HashMap<>(); HashMap<Integer, T_Bundle> bundles = new HashMap<>();
for (int deviceId : bundle.getPreKeys().keySet()) { for (int deviceId : bundle.getPreKeys().keySet()) {
try { try {
@ -255,7 +255,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return PreKeyBundle (T_PreKey) * @return PreKeyBundle (T_PreKey)
* @throws CorruptedOmemoKeyException if some key is damaged or malformed * @throws CorruptedOmemoKeyException if some key is damaged or malformed
*/ */
public abstract T_Bundle bundleFromOmemoBundle(OmemoBundleVAxolotlElement bundle, OmemoDevice contact, int keyId) throws CorruptedOmemoKeyException; public abstract T_Bundle bundleFromOmemoBundle(OmemoBundleElement bundle, OmemoDevice contact, int keyId) throws CorruptedOmemoKeyException;
/** /**
* Extract the signature from a signedPreKey. * Extract the signature from a signedPreKey.

View file

@ -41,7 +41,10 @@ import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.omemo.OmemoManager; import org.jivesoftware.smackx.omemo.OmemoManager;
import org.jivesoftware.smackx.omemo.OmemoRatchet; import org.jivesoftware.smackx.omemo.OmemoRatchet;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException; import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
@ -73,7 +76,7 @@ public class OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
private byte[] initializationVector = generateIv(); private byte[] initializationVector = generateIv();
private byte[] ciphertextMessage; private byte[] ciphertextMessage;
private final ArrayList<OmemoVAxolotlElement.OmemoHeader.Key> keys = new ArrayList<>(); private final ArrayList<OmemoKeyElement> keys = new ArrayList<>();
/** /**
* Create a OmemoMessageBuilder. * Create a OmemoMessageBuilder.
@ -211,7 +214,7 @@ public class OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
if (ignoreTrust || managerGuard.get().isTrustedOmemoIdentity(contactsDevice, fingerprint)) { if (ignoreTrust || managerGuard.get().isTrustedOmemoIdentity(contactsDevice, fingerprint)) {
// Encrypt key and save to header // Encrypt key and save to header
CiphertextTuple encryptedKey = ratchet.doubleRatchetEncrypt(contactsDevice, messageKey); CiphertextTuple encryptedKey = ratchet.doubleRatchetEncrypt(contactsDevice, messageKey);
keys.add(new OmemoVAxolotlElement.OmemoHeader.Key(encryptedKey.getCiphertext(), contactsDevice.getDeviceId(), encryptedKey.isPreKeyMessage())); keys.add(new OmemoKeyElement(encryptedKey.getCiphertext(), contactsDevice.getDeviceId(), encryptedKey.isPreKeyMessage()));
} }
} }
@ -220,13 +223,13 @@ public class OmemoMessageBuilder<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
* *
* @return OmemoMessageElement * @return OmemoMessageElement
*/ */
public OmemoVAxolotlElement finish() { public OmemoElement finish() {
OmemoVAxolotlElement.OmemoHeader header = new OmemoVAxolotlElement.OmemoHeader( OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(
managerGuard.get().getDeviceId(), managerGuard.get().getDeviceId(),
keys, keys,
initializationVector initializationVector
); );
return new OmemoVAxolotlElement(header, ciphertextMessage); return new OmemoElement_VAxolotl(header, ciphertextMessage);
} }
/** /**

View file

@ -27,7 +27,7 @@ import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoBundleElement_VAxolotl;
import org.jivesoftware.smackx.omemo.provider.OmemoBundleVAxolotlProvider; import org.jivesoftware.smackx.omemo.provider.OmemoBundleVAxolotlProvider;
import org.junit.Test; import org.junit.Test;
@ -50,7 +50,7 @@ public class OmemoBundleVAxolotlElementTest extends SmackTestSuite {
preKeysB64.put(preKeyId1, preKey1B64); preKeysB64.put(preKeyId1, preKey1B64);
preKeysB64.put(preKeyId2, preKey2B64); preKeysB64.put(preKeyId2, preKey2B64);
OmemoBundleVAxolotlElement bundle = new OmemoBundleVAxolotlElement(signedPreKeyId, OmemoBundleElement_VAxolotl bundle = new OmemoBundleElement_VAxolotl(signedPreKeyId,
signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64); signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64);
assertEquals("ElementName must match.", "bundle", bundle.getElementName()); assertEquals("ElementName must match.", "bundle", bundle.getElementName());
@ -85,7 +85,7 @@ public class OmemoBundleVAxolotlElementTest extends SmackTestSuite {
byte[] firstPreKey = "FirstPreKey".getBytes(StringUtils.UTF8); byte[] firstPreKey = "FirstPreKey".getBytes(StringUtils.UTF8);
byte[] secondPreKey = "SecondPreKey".getBytes(StringUtils.UTF8); byte[] secondPreKey = "SecondPreKey".getBytes(StringUtils.UTF8);
OmemoBundleVAxolotlElement parsed = new OmemoBundleVAxolotlProvider().parse(TestUtils.getParser(actual)); OmemoBundleElement_VAxolotl parsed = new OmemoBundleVAxolotlProvider().parse(TestUtils.getParser(actual));
assertTrue("B64-decoded signedPreKey must match.", Arrays.equals(signedPreKey, parsed.getSignedPreKey())); assertTrue("B64-decoded signedPreKey must match.", Arrays.equals(signedPreKey, parsed.getSignedPreKey()));
assertEquals("SignedPreKeyId must match", signedPreKeyId, parsed.getSignedPreKeyId()); assertEquals("SignedPreKeyId must match", signedPreKeyId, parsed.getSignedPreKeyId());

View file

@ -24,7 +24,7 @@ import java.util.HashSet;
import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
import org.jivesoftware.smackx.omemo.provider.OmemoDeviceListVAxolotlProvider; import org.jivesoftware.smackx.omemo.provider.OmemoDeviceListVAxolotlProvider;
import org.junit.Test; import org.junit.Test;
@ -41,11 +41,11 @@ public class OmemoDeviceListVAxolotlElementTest extends SmackTestSuite {
ids.add(1234); ids.add(1234);
ids.add(9876); ids.add(9876);
OmemoDeviceListVAxolotlElement element = new OmemoDeviceListVAxolotlElement(ids); OmemoDeviceListElement_VAxolotl element = new OmemoDeviceListElement_VAxolotl(ids);
String xml = element.toXML(null).toString(); String xml = element.toXML(null).toString();
XmlPullParser parser = TestUtils.getParser(xml); XmlPullParser parser = TestUtils.getParser(xml);
OmemoDeviceListVAxolotlElement parsed = new OmemoDeviceListVAxolotlProvider().parse(parser); OmemoDeviceListElement_VAxolotl parsed = new OmemoDeviceListVAxolotlProvider().parse(parser);
assertTrue("Parsed element must equal the original.", parsed.getDeviceIds().equals(element.getDeviceIds())); assertTrue("Parsed element must equal the original.", parsed.getDeviceIds().equals(element.getDeviceIds()));
assertEquals("Generated XML must match.", assertEquals("Generated XML must match.",

File diff suppressed because one or more lines are too long

View file

@ -24,9 +24,9 @@ import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoElement; import org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider; import org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider;
import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder; import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
@ -47,12 +47,12 @@ public class OmemoVAxolotlElementTest extends SmackTestSuite {
int sid = 12131415; int sid = 12131415;
byte[] iv = OmemoMessageBuilder.generateIv(); byte[] iv = OmemoMessageBuilder.generateIv();
ArrayList<OmemoElement.OmemoHeader.Key> keys = new ArrayList<>(); ArrayList<OmemoKeyElement> keys = new ArrayList<>();
keys.add(new OmemoElement.OmemoHeader.Key(keyData1, keyId1)); keys.add(new OmemoKeyElement(keyData1, keyId1));
keys.add(new OmemoElement.OmemoHeader.Key(keyData2, keyId2, true)); keys.add(new OmemoKeyElement(keyData2, keyId2, true));
OmemoVAxolotlElement.OmemoHeader header = new OmemoElement.OmemoHeader(sid, keys, iv); OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(sid, keys, iv);
OmemoVAxolotlElement element = new OmemoVAxolotlElement(header, payload); OmemoElement_VAxolotl element = new OmemoElement_VAxolotl(header, payload);
String expected = String expected =
"<encrypted xmlns='eu.siacs.conversations.axolotl'>" + "<encrypted xmlns='eu.siacs.conversations.axolotl'>" +
@ -69,7 +69,9 @@ public class OmemoVAxolotlElementTest extends SmackTestSuite {
String actual = element.toXML(null).toString(); String actual = element.toXML(null).toString();
assertEquals("Serialized xml of OmemoElement must match.", expected, actual); assertEquals("Serialized xml of OmemoElement must match.", expected, actual);
OmemoVAxolotlElement parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual)); OmemoElement_VAxolotl parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual));
assertEquals("Parsed OmemoElement must equal the original.", element.toXML(null).toString(), parsed.toXML(null).toString()); assertEquals("Parsed OmemoElement must equal the original.",
element.toXML(null).toString(),
parsed.toXML(null).toString());
} }
} }