From b0acf0bcc384c9a3a9a370fbb436b1850fc0d886 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sun, 24 Dec 2017 02:52:41 +0100 Subject: [PATCH] Temp commit --- .../omemo/signal/SignalOmemoKeyUtil.java | 4 +- .../smackx/omemo/OmemoManager.java | 88 ++--- .../smackx/omemo/OmemoRatchet.java | 9 +- .../smackx/omemo/OmemoService.java | 310 ++++++++---------- .../jivesoftware/smackx/omemo/OmemoStore.java | 59 ++-- .../omemo/element/OmemoBundleElement.java | 172 +++++++++- .../element/OmemoBundleElement_VAxolotl.java | 43 +++ .../element/OmemoBundleVAxolotlElement.java | 207 ------------ ...a => OmemoDeviceListElement_VAxolotl.java} | 4 +- .../smackx/omemo/element/OmemoElement.java | 139 ++------ .../omemo/element/OmemoElement_VAxolotl.java | 42 +++ .../omemo/element/OmemoHeaderElement.java | 82 +++++ .../element/OmemoHeaderElement_VAxolotl.java | 27 ++ .../smackx/omemo/element/OmemoKeyElement.java | 68 ++++ .../omemo/element/OmemoVAxolotlElement.java | 86 ----- .../CannotEstablishOmemoSessionException.java | 4 + .../omemo/internal/CachedDeviceList.java | 7 +- .../provider/OmemoBundleVAxolotlProvider.java | 8 +- .../OmemoDeviceListVAxolotlProvider.java | 8 +- .../omemo/provider/OmemoVAxolotlProvider.java | 44 ++- .../smackx/omemo/util/OmemoConstants.java | 4 +- .../smackx/omemo/util/OmemoKeyUtil.java | 16 +- .../omemo/util/OmemoMessageBuilder.java | 15 +- .../omemo/OmemoBundleVAxolotlElementTest.java | 6 +- .../OmemoDeviceListVAxolotlElementTest.java | 6 +- .../smack/omemo/OmemoKeyUtilTest.java | 4 +- .../smack/omemo/OmemoVAxolotlElementTest.java | 22 +- 27 files changed, 740 insertions(+), 744 deletions(-) create mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleElement_VAxolotl.java delete mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleVAxolotlElement.java rename smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/{OmemoDeviceListVAxolotlElement.java => OmemoDeviceListElement_VAxolotl.java} (87%) create mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java create mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement.java create mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement_VAxolotl.java create mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java delete mode 100644 smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoVAxolotlElement.java diff --git a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoKeyUtil.java b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoKeyUtil.java index 53663e68d..e800dfbfc 100644 --- a/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoKeyUtil.java +++ b/smack-omemo-signal/src/main/java/org/jivesoftware/smackx/omemo/signal/SignalOmemoKeyUtil.java @@ -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 payloadItem = (PayloadItem) item; - if (!(payloadItem.getPayload() instanceof OmemoDeviceListVAxolotlElement)) { + if (!(payloadItem.getPayload() instanceof OmemoDeviceListElement_VAxolotl)) { continue; } // Device 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. diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java index 4d1a4c1ef..db2f852c0 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoRatchet.java @@ -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 decryptExceptions = new ArrayList<>(); - List keys = element.getHeader().getKeys(); + // CHECKSTYLE: OFF + @SuppressWarnings("unchecked") + List 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()); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java index 98b011e4f..50c860590 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/OmemoService.java @@ -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(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(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 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) node.getItems().get(0)).getPayload(); - } catch (IndexOutOfBoundsException e) { + + List> 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 items = node.getItems(); + List> 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 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 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 messageRecipientKeys = message.getHeader().getKeys(); + // CHECKSTYLE: OFF + @SuppressWarnings("unchecked") + ArrayList 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 recipients, - Message message) + OmemoElement processSendingMessage(OmemoManager.LoggedInOmemoManager managerGuard, + ArrayList recipients, + Message message) throws CryptoFailedException, UndecidedOmemoIdentityException, NoSuchAlgorithmException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, CannotEstablishOmemoSessionException @@ -1042,9 +998,9 @@ public abstract class OmemoService> recipients, - Message message) + OmemoElement encryptOmemoMessage(OmemoManager.LoggedInOmemoManager managerGuard, + HashMap> recipients, + Message message) throws CryptoFailedException, UndecidedOmemoIdentityException { OmemoMessageBuilder @@ -1095,8 +1051,8 @@ public abstract class OmemoService signedPreKeys = loadOmemoSignedPreKeys(userDevice); if (signedPreKeys.size() == 0) { changeSignedPreKey(userDevice); - signedPreKeys = loadOmemoSignedPreKeys(userDevice); } - int currentSignedPreKeyId = signedPreKeys.lastKey(); - T_SigPreKey currentSignedPreKey = signedPreKeys.get(currentSignedPreKeyId); - TreeMap 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 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 preKeysB64; + private HashMap 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 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 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 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 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 e : preKeysB64.entrySet()) { + out += PRE_KEY_PUB + " " + PRE_KEY_ID + "=" + e.getKey() + ": " + e.getValue() + "\n"; + } + return out; + } @Override public boolean equals(Object other) { diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleElement_VAxolotl.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleElement_VAxolotl.java new file mode 100644 index 000000000..945a6611f --- /dev/null +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleElement_VAxolotl.java @@ -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 preKeysB64) { + super(signedPreKeyId, signedPreKeyB64, signedPreKeySigB64, identityKeyB64, preKeysB64); + } + + public OmemoBundleElement_VAxolotl(int signedPreKeyId, byte[] signedPreKey, byte[] signedPreKeySig, byte[] identityKey, HashMap preKeys) { + super(signedPreKeyId, signedPreKey, signedPreKeySig, identityKey, preKeys); + } + + @Override + public String getNamespace() { + return OMEMO_NAMESPACE_V_AXOLOTL; + } +} diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleVAxolotlElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleVAxolotlElement.java deleted file mode 100644 index d27df5d87..000000000 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoBundleVAxolotlElement.java +++ /dev/null @@ -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 preKeysB64; - private HashMap 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 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 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 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 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 e : preKeysB64.entrySet()) { - out += PRE_KEY_PUB + " " + PRE_KEY_ID + "=" + e.getKey() + ": " + e.getValue() + "\n"; - } - return out; - } -} diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListVAxolotlElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListElement_VAxolotl.java similarity index 87% rename from smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListVAxolotlElement.java rename to smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListElement_VAxolotl.java index 197566c5d..daa21d217 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListVAxolotlElement.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoDeviceListElement_VAxolotl.java @@ -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 deviceIds) { + public OmemoDeviceListElement_VAxolotl(Set deviceIds) { super(deviceIds); } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement.java index 4d8c5dfa6..27db720b9 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement.java @@ -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 keys; - private final byte[] iv; + @Override + public XmlStringBuilder toXML(String enclosingNamespace) { + XmlStringBuilder sb = new XmlStringBuilder(this, enclosingNamespace).rightAngleBracket(); - public OmemoHeader(int sid, ArrayList 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 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; } } diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java new file mode 100644 index 000000000..49d77ad40 --- /dev/null +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoElement_VAxolotl.java @@ -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; + } +} diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement.java new file mode 100644 index 000000000..37cedf64e --- /dev/null +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement.java @@ -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 keys; + private final byte[] iv; + + public OmemoHeaderElement(int sid, ArrayList 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 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); + } + + +} \ No newline at end of file diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement_VAxolotl.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement_VAxolotl.java new file mode 100644 index 000000000..018a9acaf --- /dev/null +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoHeaderElement_VAxolotl.java @@ -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 keys, byte[] iv) { + super(sid, keys, iv); + } + +} diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java new file mode 100644 index 000000000..610c941b5 --- /dev/null +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoKeyElement.java @@ -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; + } +} \ No newline at end of file diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoVAxolotlElement.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoVAxolotlElement.java deleted file mode 100644 index 3f189d594..000000000 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/element/OmemoVAxolotlElement.java +++ /dev/null @@ -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); - } - } -} diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/CannotEstablishOmemoSessionException.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/CannotEstablishOmemoSessionException.java index d8b25bbab..df98a7248 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/CannotEstablishOmemoSessionException.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/exceptions/CannotEstablishOmemoSessionException.java @@ -35,6 +35,10 @@ public class CannotEstablishOmemoSessionException extends Exception { private final HashMap> failures = new HashMap<>(); private final HashMap> successes = new HashMap<>(); + public CannotEstablishOmemoSessionException() { + super(); + } + public CannotEstablishOmemoSessionException(OmemoDevice failed, Throwable reason) { super(); getFailsOfContact(failed.getJid()).put(failed, reason); diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CachedDeviceList.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CachedDeviceList.java index f518881cc..7efca2ce5 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CachedDeviceList.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/internal/CachedDeviceList.java @@ -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: ["; diff --git a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/provider/OmemoBundleVAxolotlProvider.java b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/provider/OmemoBundleVAxolotlProvider.java index 2fcd3ad04..d79aea302 100644 --- a/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/provider/OmemoBundleVAxolotlProvider.java +++ b/smack-omemo/src/main/java/org/jivesoftware/smackx/omemo/provider/OmemoBundleVAxolotlProvider.java @@ -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 { +public class OmemoBundleVAxolotlProvider extends ExtensionElementProvider { @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 { +public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider { @Override - public OmemoDeviceListVAxolotlElement parse(XmlPullParser parser, int initialDepth) throws Exception { + public OmemoDeviceListElement_VAxolotl parse(XmlPullParser parser, int initialDepth) throws Exception { Set deviceListIds = new HashSet<>(); boolean stop = false; while (!stop) { @@ -63,6 +63,6 @@ public class OmemoDeviceListVAxolotlProvider extends ExtensionElementProvider { +public class OmemoVAxolotlProvider extends ExtensionElementProvider { @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 keys = new ArrayList<>(); + ArrayList keys = new ArrayList<>(); byte[] iv = null; byte[] payload = null; @@ -57,41 +53,41 @@ public class OmemoVAxolotlProvider extends ExtensionElementProvider bundles(OmemoBundleVAxolotlElement bundle, OmemoDevice contact) throws CorruptedOmemoKeyException { + public HashMap bundles(OmemoBundleElement bundle, OmemoDevice contact) throws CorruptedOmemoKeyException { HashMap bundles = new HashMap<>(); for (int deviceId : bundle.getPreKeys().keySet()) { try { @@ -255,7 +255,7 @@ public abstract class OmemoKeyUtil keys = new ArrayList<>(); + private final ArrayList keys = new ArrayList<>(); /** * Create a OmemoMessageBuilder. @@ -211,7 +214,7 @@ public class OmemoMessageBuilder bundles = keyUtil.BUNDLE.bundles(bundle, device); assertEquals("There must be 100 bundles in the HashMap.", 100, bundles.size()); diff --git a/smack-omemo/src/test/java/org/jivesoftware/smack/omemo/OmemoVAxolotlElementTest.java b/smack-omemo/src/test/java/org/jivesoftware/smack/omemo/OmemoVAxolotlElementTest.java index 12030e5c9..084fa2f09 100644 --- a/smack-omemo/src/test/java/org/jivesoftware/smack/omemo/OmemoVAxolotlElementTest.java +++ b/smack-omemo/src/test/java/org/jivesoftware/smack/omemo/OmemoVAxolotlElementTest.java @@ -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 keys = new ArrayList<>(); - keys.add(new OmemoElement.OmemoHeader.Key(keyData1, keyId1)); - keys.add(new OmemoElement.OmemoHeader.Key(keyData2, keyId2, true)); + ArrayList 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 = "" + @@ -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()); } }