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.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.internal.OmemoDevice;
import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;
@ -141,7 +141,7 @@ public class SignalOmemoKeyUtil extends OmemoKeyUtil<IdentityKeyPair, IdentityKe
}
@Override
public PreKeyBundle bundleFromOmemoBundle(OmemoBundleVAxolotlElement bundle, OmemoDevice contact, int preKeyId)
public PreKeyBundle bundleFromOmemoBundle(OmemoBundleElement bundle, OmemoDevice contact, int preKeyId)
throws CorruptedOmemoKeyException
{
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.MultiUserChatManager;
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.OmemoVAxolotlElement;
import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
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.
* If there was an OmemoManager for the connection and id before, return it. Otherwise create a new OmemoManager
* instance and return it.
*
* @param connection XmppConnection.
* @param deviceId MUST NOT be null and MUST be greater than 0.
* @return
*
* @return manager
*/
public synchronized static OmemoManager getInstanceFor(XMPPConnection connection, Integer deviceId) {
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
* before, create a new one. If there was one before, return it. If there were multiple managers before, return the
* one with the lowest deviceId.
* Returns an OmemoManager instance for the given connection. If there was one manager for the connection before,
* return it. If there were multiple managers before, return the 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.
*
* @return manager
*/
public synchronized static OmemoManager getInstanceFor(XMPPConnection connection) {
@ -201,7 +206,9 @@ public final class OmemoManager extends Manager {
/**
* 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) {
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
* 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) {
Async.go(new Runnable() {
@ -257,7 +265,7 @@ public final class OmemoManager extends Manager {
* OMEMO encrypt a cleartext message for a single recipient.
* 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
* @return encrypted message
* @throws CryptoFailedException when something crypto related fails
@ -278,7 +286,7 @@ public final class OmemoManager extends Manager {
LoggedInOmemoManager guard = new LoggedInOmemoManager(this);
Message plaintext = new Message();
plaintext.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService().processSendingMessage(guard, to, plaintext);
OmemoElement encrypted = getOmemoService().processSendingMessage(guard, to, plaintext);
return finishMessage(encrypted);
}
}
@ -306,7 +314,7 @@ public final class OmemoManager extends Manager {
synchronized (LOCK) {
Message m = new Message();
m.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService().processSendingMessage(
OmemoElement encrypted = getOmemoService().processSendingMessage(
new LoggedInOmemoManager(this), recipients, m);
return finishMessage(encrypted);
}
@ -368,7 +376,7 @@ public final class OmemoManager extends Manager {
synchronized (LOCK) {
Message m = new Message();
m.setBody(message);
OmemoVAxolotlElement encrypted = getOmemoService()
OmemoElement encrypted = getOmemoService()
.encryptOmemoMessage(new LoggedInOmemoManager(this), exception.getSuccesses(), m);
return finishMessage(encrypted);
}
@ -482,43 +490,6 @@ public final class OmemoManager extends Manager {
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
* secrecy.
@ -552,7 +523,7 @@ public final class OmemoManager extends Manager {
* @throws CryptoFailedException When something fails with the crypto
* @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,
CannotEstablishOmemoSessionException, SmackException.NotLoggedInException
{
@ -571,7 +542,7 @@ public final class OmemoManager extends Manager {
* @param encrypted OmemoMessageElement
* @return Message containing the OMEMO element and some additional information
*/
Message finishMessage(OmemoVAxolotlElement encrypted) {
Message finishMessage(OmemoElement encrypted) {
if (encrypted == null) {
return null;
}
@ -794,8 +765,7 @@ public final class OmemoManager extends Manager {
// generate key
getOmemoService().getOmemoStoreBackend().changeSignedPreKey(getOwnDevice());
// publish
getOmemoService().publishDeviceIdIfNeeded(managerGuard, false);
getOmemoService().publishBundle(managerGuard);
getOmemoService().publish(managerGuard);
}
}
@ -805,7 +775,7 @@ public final class OmemoManager extends Manager {
* @return true if stanza has extension 'encrypted'
*/
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;
if (!(payloadItem.getPayload() instanceof OmemoDeviceListVAxolotlElement)) {
if (!(payloadItem.getPayload() instanceof OmemoDeviceListElement_VAxolotl)) {
continue;
}
// Device List <list>
OmemoDeviceListVAxolotlElement omemoDeviceListElement =
(OmemoDeviceListVAxolotlElement) payloadItem.getPayload();
OmemoDeviceListElement_VAxolotl omemoDeviceListElement =
(OmemoDeviceListElement_VAxolotl) payloadItem.getPayload();
Integer ourDeviceId = getDeviceId();
getOmemoService().getOmemoStoreBackend()
@ -1047,8 +1017,8 @@ public final class OmemoManager extends Manager {
// enroll at the deviceList
deviceListIds.add(ourDeviceId);
final OmemoDeviceListVAxolotlElement newOmemoDeviceListElement =
new OmemoDeviceListVAxolotlElement(deviceListIds);
final OmemoDeviceListElement_VAxolotl newOmemoDeviceListElement =
new OmemoDeviceListElement_VAxolotl(deviceListIds);
// PEPListener is a synchronous listener.
// 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.util.StringUtils;
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.CryptoFailedException;
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();
byte[] unpackedKey = null;
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.
for (OmemoElement.OmemoHeader.Key k : keys) {
for (OmemoKeyElement k : keys) {
if (k.getId() == keyId) {
try {
unpackedKey = doubleRatchetDecrypt(sender, k.getData());

View File

@ -30,7 +30,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
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.MultiUserChatManager;
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.OmemoDeviceListVAxolotlElement;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
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.CorruptedOmemoKeyException;
import org.jivesoftware.smackx.omemo.exceptions.CryptoFailedException;
@ -206,6 +204,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
checkAvailableAlgorithms();
}
/**
* Makes the OmemoManager known to the OmemoService.
* @param manager manager.
*/
void registerManager(OmemoManager manager) {
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 SmackException.NotConnectedException
* @throws SmackException.NoResponseException
* @throws SmackException.NotLoggedInException
* @throws PubSubException.NotALeafNodeException
*/
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,
PubSubException.NotALeafNodeException
{
OmemoManager manager = managerGuard.get();
OmemoDevice userDevice = manager.getOwnDevice();
// Create new keys if necessary and publish to the server.
publishBundle(managerGuard);
// Get fresh device list from server
refreshOwnDeviceList(managerGuard);
publishDeviceIdIfNeeded(managerGuard, false);
CachedDeviceList list = refreshOwnDeviceList(managerGuard);
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, "");
}
/**
* 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.
*
@ -319,70 +301,6 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
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.
* 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()
* @param managerGuard OmemoManager
* @param deviceList list of deviceIDs
* @throws InterruptedException Exception
* @throws XMPPException.XMPPErrorException Exception
* @throws SmackException.NotConnectedException Exception
* @throws SmackException.NoResponseException Exception
* @throws PubSubException.NotALeafNodeException Exception
* @throws InterruptedException Exception
* @throws XMPPException.XMPPErrorException Exception
* @throws SmackException.NotConnectedException Exception
* @throws SmackException.NoResponseException Exception
* @throws PubSubException.NotALeafNodeException Exception
*/
static void publishDeviceIds(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDeviceListElement deviceList)
throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException,
@ -482,39 +400,17 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws NotAPubSubNodeException
*/
static OmemoDeviceListElement fetchDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException
{
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();
throws InterruptedException, SmackException.NotConnectedException, SmackException.NoResponseException,
XMPPException.XMPPErrorException {
try {
getOmemoStoreBackend().mergeCachedDeviceList(userDevice, userDevice.getJid(),
fetchDeviceList(managerGuard, omemoManager.getOwnJid()));
return extractDeviceListFrom(fetchDeviceListNode(managerGuard, contact));
}
} catch (XMPPException.XMPPErrorException e) {
catch (XMPPException.XMPPErrorException e) {
if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) {
LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the node did not exist: "
+ e.getMessage());
return true;
}
throw e;
@ -522,15 +418,35 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
} catch (PubSubException.NotALeafNodeException e) {
LOGGER.log(Level.WARNING, "Could not refresh own deviceList, because the Node is not a LeafNode: " +
e.getMessage());
return true;
}
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.");
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 SmackException.NoResponseException
*/
void refreshDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact)
CachedDeviceList refreshDeviceList(OmemoManager.LoggedInOmemoManager managerGuard, BareJid contact)
throws SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException
{
OmemoDeviceListElement omemoDeviceListElement;
OmemoDeviceListElement omemoDeviceListElement = null;
try {
omemoDeviceListElement = fetchDeviceList(managerGuard, contact);
} catch (PubSubException.NotALeafNodeException | XMPPException.XMPPErrorException | NotAPubSubNodeException e) {
} catch (XMPPException.XMPPErrorException 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 NotAPubSubNodeException
*/
static OmemoBundleVAxolotlElement fetchBundle(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contact)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException
static OmemoBundleElement fetchBundle(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contact)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException, PubSubException.NotALeafNodeException, NotAPubSubNodeException
{
OmemoManager omemoManager = managerGuard.get();
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);
}
@ -590,22 +504,26 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws InterruptedException goes
* @throws SmackException.NoResponseException wrong
*/
private static OmemoBundleVAxolotlElement extractBundleFrom(LeafNode node)
private static OmemoBundleElement extractBundleFrom(LeafNode node)
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException
{
if (node == null) {
return null;
}
try {
return (OmemoBundleVAxolotlElement) ((PayloadItem<?>) node.getItems().get(0)).getPayload();
} catch (IndexOutOfBoundsException e) {
List<PayloadItem<OmemoBundleElement>> bundleItems = node.getItems();
if (bundleItems.isEmpty()) {
return null;
}
return bundleItems.get(0).getPayload();
}
/**
* 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
* @return the extracted OmemoDeviceListElement.
@ -623,11 +541,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
return null;
}
List<?> items = node.getItems();
List<PayloadItem<OmemoDeviceListElement>> items = node.getItems();
if (items.size() > 0) {
OmemoDeviceListVAxolotlElement listElement =
(OmemoDeviceListVAxolotlElement) ((PayloadItem<?>) items.get(items.size() - 1)).getPayload();
OmemoDeviceListElement listElement = items.get(items.size() - 1).getPayload();
if (items.size() > 1) {
node.deleteAllItems();
@ -638,7 +555,42 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
}
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;
}
OmemoBundleVAxolotlElement bundle;
OmemoBundleElement bundle;
try {
bundle = fetchBundle(managerGuard, contactsDevice);
} 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.
*
* @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
* @return decrypted message or null
* @throws NoRawSessionException
@ -771,7 +723,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
*/
private Message processReceivingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
OmemoDevice contactsDevice,
OmemoElement message,
OmemoElement omemoElement,
final OmemoMessageInformation information)
throws NoRawSessionException, InterruptedException, SmackException.NoResponseException,
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();
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?
for (OmemoVAxolotlElement.OmemoHeader.Key k : messageRecipientKeys) {
for (OmemoKeyElement k : messageRecipientKeys) {
// Only decrypt with our deviceID
if (k.getId() != omemoManager.getDeviceId()) {
continue;
}
Message decrypted = decryptOmemoMessageElement(managerGuard, contactsDevice, message, information);
Message decrypted = decryptOmemoMessageElement(managerGuard, contactsDevice, omemoElement, information);
if (contactsDevice.equals(omemoManager.getOwnJid()) && decrypted != null) {
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
{
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();
Message decrypted = processReceivingMessage(managerGuard,
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 NoSuchAlgorithmException
*/
OmemoVAxolotlElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
BareJid recipient,
Message message)
OmemoElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
BareJid recipient,
Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException,
SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
CannotEstablishOmemoSessionException
@ -871,9 +827,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws UndecidedOmemoIdentityException
* @throws NoSuchAlgorithmException
*/
OmemoVAxolotlElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
ArrayList<BareJid> recipients,
Message message)
OmemoElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard,
ArrayList<BareJid> recipients,
Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException,
SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException,
CannotEstablishOmemoSessionException
@ -1042,9 +998,9 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
*
* @return OmemoMessageElement
*/
OmemoVAxolotlElement encryptOmemoMessage(OmemoManager.LoggedInOmemoManager managerGuard,
HashMap<BareJid, ArrayList<OmemoDevice>> recipients,
Message message)
OmemoElement encryptOmemoMessage(OmemoManager.LoggedInOmemoManager managerGuard,
HashMap<BareJid, ArrayList<OmemoDevice>> recipients,
Message message)
throws CryptoFailedException, UndecidedOmemoIdentityException
{
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 CannotEstablishOmemoSessionException
*/
OmemoVAxolotlElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
OmemoDevice... recipients)
OmemoElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
OmemoDevice... recipients)
throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException,
CannotEstablishOmemoSessionException
{
@ -1130,10 +1086,10 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @throws CorruptedOmemoKeyException
* @throws CannotEstablishOmemoSessionException
*/
OmemoVAxolotlElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
byte[] aesKey,
byte[] iv,
OmemoDevice... recipients)
OmemoElement prepareOmemoKeyTransportElement(OmemoManager.LoggedInOmemoManager managerGuard,
byte[] aesKey,
byte[] iv,
OmemoDevice... recipients)
throws CryptoFailedException, UndecidedOmemoIdentityException, CorruptedOmemoKeyException,
CannotEstablishOmemoSessionException
{
@ -1177,7 +1133,7 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
buildSessionWithDevice(managerGuard, recipient, true);
}
OmemoVAxolotlElement keyTransportElement = prepareOmemoKeyTransportElement(managerGuard, recipient);
OmemoElement keyTransportElement = prepareOmemoKeyTransportElement(managerGuard, recipient);
Message ratchetUpdateMessage = managerGuard.get().finishMessage(keyTransportElement);
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,
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();
if (isMucMessage(managerGuard, stanza)) {
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) {
OmemoManager omemoManager = managerGuard.get();
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();
MultiUserChatManager mucm = MultiUserChatManager.getInstanceFor(omemoManager.getConnection());
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);
Message decrypted;
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();
if (CarbonExtension.Direction.received.equals(direction)) {

View File

@ -16,7 +16,7 @@
*/
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.HashMap;
@ -26,7 +26,7 @@ import java.util.TreeMap;
import java.util.logging.Level;
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.exceptions.CannotEstablishOmemoSessionException;
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 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);
if (cached == null) {
@ -108,8 +108,10 @@ public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_
if (list != null) {
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.
* 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.
* @return OmemoBundleElement
* @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
{
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);
if (signedPreKeys.size() == 0) {
changeSignedPreKey(userDevice);
signedPreKeys = loadOmemoSignedPreKeys(userDevice);
}
int currentSignedPreKeyId = signedPreKeys.lastKey();
T_SigPreKey currentSignedPreKey = signedPreKeys.get(currentSignedPreKeyId);
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();
if (newKeysCount > 0) {
TreeMap<Integer, T_PreKey> newKeys = generateOmemoPreKeys(startId + 1, newKeysCount);
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*
@ -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 int loadCurrentOmemoSignedPreKeyId(OmemoDevice userDevice) {
return loadOmemoSignedPreKeys(userDevice).lastKey();
}
/**
* 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);
/**
* 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.
* See this as a cache.

View File

@ -16,12 +16,15 @@
*/
package org.jivesoftware.smackx.omemo.element;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* Class that represents an OMEMO Bundle element.
* TODO: Move functionality to here.
*
* @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_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
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
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
*/
public class OmemoDeviceListVAxolotlElement extends OmemoDeviceListElement {
public class OmemoDeviceListElement_VAxolotl extends OmemoDeviceListElement {
public OmemoDeviceListVAxolotlElement(Set<Integer> deviceIds) {
public OmemoDeviceListElement_VAxolotl(Set<Integer> deviceIds) {
super(deviceIds);
}

View File

@ -16,17 +16,13 @@
*/
package org.jivesoftware.smackx.omemo.element;
import java.util.ArrayList;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
/**
* Class that represents an OmemoElement.
* TODO: Move functionality here.
*
* @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_MESSAGE = 0;
public static final String ENCRYPTED = "encrypted";
public static final String HEADER = "header";
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";
public static final String NAME_ENCRYPTED = "encrypted";
public static final String ATTR_PAYLOAD = "payload";
protected final OmemoElement.OmemoHeader header;
protected final byte[] payload;
private final OmemoHeaderElement header;
private final byte[] 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 payload payload
*/
public OmemoElement(OmemoElement.OmemoHeader header, byte[] payload) {
public OmemoElement(OmemoHeaderElement header, byte[] payload) {
this.header = Objects.requireNonNull(header);
this.payload = payload;
}
public OmemoElement.OmemoHeader getHeader() {
public OmemoHeaderElement getHeader() {
return header;
}
@ -82,113 +72,22 @@ public abstract class OmemoElement implements ExtensionElement {
return payload != null;
}
/**
* 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 static class OmemoHeader implements NamedElement {
private final int sid;
private final ArrayList<Key> keys;
private final byte[] iv;
@Override
public XmlStringBuilder toXML(String enclosingNamespace) {
XmlStringBuilder sb = new XmlStringBuilder(this, enclosingNamespace).rightAngleBracket();
public OmemoHeader(int sid, ArrayList<OmemoHeader.Key> keys, byte[] iv) {
this.sid = sid;
this.keys = keys;
this.iv = iv;
sb.element(header);
if (payload != null) {
sb.openElement(ATTR_PAYLOAD).append(Base64.encodeToString(payload)).closeElement(ATTR_PAYLOAD);
}
/**
* Return the deviceId of the sender of the message.
*
* @return senders id
*/
public int getSid() {
return sid;
}
sb.closeElement(this);
return sb;
}
public ArrayList<OmemoHeader.Key> getKeys() {
return new ArrayList<>(keys);
}
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;
}
}
@Override
public String getElementName() {
return NAME_ENCRYPTED;
}
}

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, ArrayList<OmemoDevice>> successes = new HashMap<>();
public CannotEstablishOmemoSessionException() {
super();
}
public CannotEstablishOmemoSessionException(OmemoDevice failed, Throwable reason) {
super();
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
*/
public void addDevice(int deviceId) {
activeDevices.add(deviceId);
inactiveDevices.remove(deviceId);
}
/**
@ -118,6 +119,10 @@ public class CachedDeviceList implements Serializable {
return activeDevices.contains(deviceId) || inactiveDevices.contains(deviceId);
}
public boolean isActive(int deviceId) {
return getActiveDevices().contains(deviceId);
}
@Override
public String toString() {
String out = "active: [";

View File

@ -31,7 +31,7 @@ import java.util.HashMap;
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;
@ -40,9 +40,9 @@ import org.xmlpull.v1.XmlPullParser;
*
* @author Paul Schaub
*/
public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoBundleVAxolotlElement> {
public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoBundleElement_VAxolotl> {
@Override
public OmemoBundleVAxolotlElement parse(XmlPullParser parser, int initialDepth) throws Exception {
public OmemoBundleElement_VAxolotl parse(XmlPullParser parser, int initialDepth) throws Exception {
boolean stop = false;
boolean inPreKeys = false;
@ -96,6 +96,6 @@ public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider<OmemoB
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.smackx.omemo.element.OmemoDeviceListVAxolotlElement;
import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement_VAxolotl;
import org.xmlpull.v1.XmlPullParser;
@ -36,10 +36,10 @@ import org.xmlpull.v1.XmlPullParser;
*
* @author Paul Schaub
*/
public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<OmemoDeviceListVAxolotlElement> {
public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<OmemoDeviceListElement_VAxolotl> {
@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<>();
boolean stop = false;
while (!stop) {
@ -63,6 +63,6 @@ public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider<Om
break;
}
}
return new OmemoDeviceListVAxolotlElement(deviceListIds);
return new OmemoDeviceListElement_VAxolotl(deviceListIds);
}
}

View File

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

View File

@ -37,7 +37,7 @@ public final class OmemoConstants {
/**
* 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.
@ -49,7 +49,7 @@ public final class OmemoConstants {
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.

View File

@ -23,7 +23,7 @@ import java.util.TreeMap;
import java.util.logging.Level;
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.internal.OmemoDevice;
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
* @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());
}
@ -70,7 +70,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return singedPreKey
* @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());
}
@ -80,7 +80,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @param bundle OmemoBundleElement
* @return signedPreKeyId
*/
public int signedPreKeyId(OmemoBundleVAxolotlElement bundle) {
public int signedPreKeyId(OmemoBundleElement bundle) {
return bundle.getSignedPreKeyId();
}
@ -90,7 +90,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @param bundle OmemoBundleElement
* @return signature
*/
public byte[] signedPreKeySignature(OmemoBundleVAxolotlElement bundle) {
public byte[] signedPreKeySignature(OmemoBundleElement bundle) {
return bundle.getSignedPreKeySignature();
}
@ -102,7 +102,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return the preKey
* @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));
}
@ -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
* @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<>();
for (int deviceId : bundle.getPreKeys().keySet()) {
try {
@ -255,7 +255,7 @@ public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
* @return PreKeyBundle (T_PreKey)
* @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.

View File

@ -41,7 +41,10 @@ import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.omemo.OmemoManager;
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.CorruptedOmemoKeyException;
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[] ciphertextMessage;
private final ArrayList<OmemoVAxolotlElement.OmemoHeader.Key> keys = new ArrayList<>();
private final ArrayList<OmemoKeyElement> keys = new ArrayList<>();
/**
* 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)) {
// Encrypt key and save to header
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
*/
public OmemoVAxolotlElement finish() {
OmemoVAxolotlElement.OmemoHeader header = new OmemoVAxolotlElement.OmemoHeader(
public OmemoElement finish() {
OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(
managerGuard.get().getDeviceId(),
keys,
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.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.junit.Test;
@ -50,7 +50,7 @@ public class OmemoBundleVAxolotlElementTest extends SmackTestSuite {
preKeysB64.put(preKeyId1, preKey1B64);
preKeysB64.put(preKeyId2, preKey2B64);
OmemoBundleVAxolotlElement bundle = new OmemoBundleVAxolotlElement(signedPreKeyId,
OmemoBundleElement_VAxolotl bundle = new OmemoBundleElement_VAxolotl(signedPreKeyId,
signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64);
assertEquals("ElementName must match.", "bundle", bundle.getElementName());
@ -85,7 +85,7 @@ public class OmemoBundleVAxolotlElementTest extends SmackTestSuite {
byte[] firstPreKey = "FirstPreKey".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()));
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.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.junit.Test;
@ -41,11 +41,11 @@ public class OmemoDeviceListVAxolotlElementTest extends SmackTestSuite {
ids.add(1234);
ids.add(9876);
OmemoDeviceListVAxolotlElement element = new OmemoDeviceListVAxolotlElement(ids);
OmemoDeviceListElement_VAxolotl element = new OmemoDeviceListElement_VAxolotl(ids);
String xml = element.toXML(null).toString();
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()));
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.util.StringUtils;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.omemo.element.OmemoElement;
import org.jivesoftware.smackx.omemo.element.OmemoVAxolotlElement;
import org.jivesoftware.smackx.omemo.element.OmemoElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoHeaderElement_VAxolotl;
import org.jivesoftware.smackx.omemo.element.OmemoKeyElement;
import org.jivesoftware.smackx.omemo.provider.OmemoVAxolotlProvider;
import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;
@ -47,12 +47,12 @@ public class OmemoVAxolotlElementTest extends SmackTestSuite {
int sid = 12131415;
byte[] iv = OmemoMessageBuilder.generateIv();
ArrayList<OmemoElement.OmemoHeader.Key> keys = new ArrayList<>();
keys.add(new OmemoElement.OmemoHeader.Key(keyData1, keyId1));
keys.add(new OmemoElement.OmemoHeader.Key(keyData2, keyId2, true));
ArrayList<OmemoKeyElement> keys = new ArrayList<>();
keys.add(new OmemoKeyElement(keyData1, keyId1));
keys.add(new OmemoKeyElement(keyData2, keyId2, true));
OmemoVAxolotlElement.OmemoHeader header = new OmemoElement.OmemoHeader(sid, keys, iv);
OmemoVAxolotlElement element = new OmemoVAxolotlElement(header, payload);
OmemoHeaderElement_VAxolotl header = new OmemoHeaderElement_VAxolotl(sid, keys, iv);
OmemoElement_VAxolotl element = new OmemoElement_VAxolotl(header, payload);
String expected =
"<encrypted xmlns='eu.siacs.conversations.axolotl'>" +
@ -69,7 +69,9 @@ public class OmemoVAxolotlElementTest extends SmackTestSuite {
String actual = element.toXML(null).toString();
assertEquals("Serialized xml of OmemoElement must match.", expected, actual);
OmemoVAxolotlElement parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual));
assertEquals("Parsed OmemoElement must equal the original.", element.toXML(null).toString(), parsed.toXML(null).toString());
OmemoElement_VAxolotl parsed = new OmemoVAxolotlProvider().parse(TestUtils.getParser(actual));
assertEquals("Parsed OmemoElement must equal the original.",
element.toXML(null).toString(),
parsed.toXML(null).toString());
}
}