/** * * 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; import static org.jivesoftware.smackx.omemo.util.OmemoConstants.TARGET_PRE_KEY_COUNT; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.roster.Roster; import org.jivesoftware.smack.roster.RosterEntry; import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement; import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement; import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException; import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException; import org.jivesoftware.smackx.omemo.internal.CachedDeviceList; import org.jivesoftware.smackx.omemo.internal.OmemoDevice; import org.jivesoftware.smackx.omemo.internal.OmemoSession; import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil; import org.jxmpp.jid.BareJid; /** * Class that presents some methods that are used to load/generate/store keys and session data needed for OMEMO. * * @param IdentityKeyPair class * @param IdentityKey class * @param PreKey class * @param SignedPreKey class * @param Session class * @param Address class * @param Elliptic Curve PublicKey class * @param Bundle class * @param Cipher class * @author Paul Schaub */ public abstract class OmemoStore { private static final Logger LOGGER = Logger.getLogger(OmemoStore.class.getName()); private final WeakHashMap>> omemoSessions = new WeakHashMap<>(); /** * Create a new OmemoStore. */ public OmemoStore() { } /** * Return true if this is a fresh installation. * * @param omemoManager omemoManager of our device. * @return true or false. */ public abstract boolean isFreshInstallation(OmemoManager omemoManager); /** * Check, if our freshly generated deviceId is available (unique) in our deviceList. * * @param omemoManager omemoManager of our device. * @param id our deviceId. * @return true if list did not contain our id, else false */ boolean isAvailableDeviceId(OmemoManager omemoManager, int id) { LOGGER.log(Level.INFO, "Check if id " + id + " is available..."); // Lookup local cached device list BareJid ownJid = omemoManager.getOwnJid(); CachedDeviceList cachedDeviceList = loadCachedDeviceList(omemoManager, ownJid); if (cachedDeviceList == null) { cachedDeviceList = new CachedDeviceList(); } // Does the list already contain that id? return !cachedDeviceList.contains(id); } /** * Generate a new Identity (deviceId, identityKeys, preKeys...). * * @param omemoManager omemoManager of our device we want to regenerate. * @throws CorruptedOmemoKeyException in case something goes wrong */ void regenerate(OmemoManager omemoManager) throws CorruptedOmemoKeyException { LOGGER.log(Level.INFO, "Regenerating with deviceId " + omemoManager.getDeviceId() + "..."); int nextPreKeyId = 1; storeOmemoIdentityKeyPair(omemoManager, generateOmemoIdentityKeyPair()); storeOmemoPreKeys(omemoManager, generateOmemoPreKeys(nextPreKeyId, TARGET_PRE_KEY_COUNT)); storeLastPreKeyId(omemoManager, OmemoKeyUtil.addInBounds(nextPreKeyId, TARGET_PRE_KEY_COUNT)); storeCurrentSignedPreKeyId(omemoManager, -1); //Set back to no-value default changeSignedPreKey(omemoManager); initializeOmemoSessions(omemoManager); } /** * Merge the received OmemoDeviceListElement with the one we already have. If we had none, the received one is saved. * * @param omemoManager omemoManager of our device. * @param contact Contact we received the list from. * @param list List we received. */ void mergeCachedDeviceList(OmemoManager omemoManager, BareJid contact, OmemoDeviceListElement list) { CachedDeviceList cached = loadCachedDeviceList(omemoManager, contact); if (cached == null) { cached = new CachedDeviceList(); } if (list != null) { cached.merge(list.getDeviceIds()); } storeCachedDeviceList(omemoManager, contact, cached); } /** * Renew our singed preKey. This should be done once every 7-14 days. * The old signed PreKey should be kept for around a month or so (look it up in the XEP). * * @param omemoManager omemoManager of our device. * @throws CorruptedOmemoKeyException when our identityKey is invalid */ void changeSignedPreKey(OmemoManager omemoManager) throws CorruptedOmemoKeyException { int lastSignedPreKeyId = loadCurrentSignedPreKeyId(omemoManager); if (lastSignedPreKeyId == -1) lastSignedPreKeyId = 0; try { T_SigPreKey newSignedPreKey = generateOmemoSignedPreKey(loadOmemoIdentityKeyPair(omemoManager), lastSignedPreKeyId + 1); storeOmemoSignedPreKey(omemoManager, lastSignedPreKeyId + 1, newSignedPreKey); storeCurrentSignedPreKeyId(omemoManager, lastSignedPreKeyId + 1); setDateOfLastSignedPreKeyRenewal(omemoManager); removeOldSignedPreKeys(omemoManager); } catch (CorruptedOmemoKeyException e) { LOGGER.log(Level.INFO, "Couldn't change SignedPreKey: " + e.getMessage()); throw e; } } /** * Remove the oldest signedPreKey until there are only MAX_NUMBER_OF_STORED_SIGNED_PREKEYS left. * * @param omemoManager omemoManager of our device. */ private void removeOldSignedPreKeys(OmemoManager omemoManager) { if (OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys() <= 0) { return; } int currentId = loadCurrentSignedPreKeyId(omemoManager); if (currentId == -1) currentId = 0; HashMap signedPreKeys = loadOmemoSignedPreKeys(omemoManager); for (int i : signedPreKeys.keySet()) { if (i <= currentId - OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys()) { LOGGER.log(Level.INFO, "Remove signedPreKey " + i + "."); removeOmemoSignedPreKey(omemoManager, i); } } } /** * 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. * * @param omemoManager omemoManager of our device. * @return OmemoBundleElement * @throws CorruptedOmemoKeyException when a key could not be loaded */ OmemoBundleVAxolotlElement packOmemoBundle(OmemoManager omemoManager) throws CorruptedOmemoKeyException { int currentSignedPreKeyId = loadCurrentSignedPreKeyId(omemoManager); if (currentSignedPreKeyId == -1) currentSignedPreKeyId = 0; T_SigPreKey currentSignedPreKey = loadOmemoSignedPreKey(omemoManager, currentSignedPreKeyId); T_IdKeyPair identityKeyPair = loadOmemoIdentityKeyPair(omemoManager); HashMap preKeys = loadOmemoPreKeys(omemoManager); int newKeysCount = TARGET_PRE_KEY_COUNT - preKeys.size(); if (newKeysCount > 0) { int lastPreKeyId = loadLastPreKeyId(omemoManager); if (lastPreKeyId == -1) lastPreKeyId = 0; HashMap newKeys = generateOmemoPreKeys(lastPreKeyId + 1, newKeysCount); storeOmemoPreKeys(omemoManager, newKeys); preKeys.putAll(newKeys); storeLastPreKeyId(omemoManager, lastPreKeyId + newKeysCount); } return new OmemoBundleVAxolotlElement( currentSignedPreKeyId, keyUtil().signedPreKeyPublicForBundle(currentSignedPreKey), keyUtil().signedPreKeySignatureFromKey(currentSignedPreKey), keyUtil().identityKeyForBundle(keyUtil().identityKeyFromPair(identityKeyPair)), keyUtil().preKeyPublisKeysForBundle(preKeys) ); } /** * Preload all OMEMO sessions for our devices and our contacts from existing raw sessions. * * @param omemoManager omemoManager of our device. */ void initializeOmemoSessions(OmemoManager omemoManager) { // Get HashMap of our omemoSessions HashMap> sessions = omemoSessions.get(omemoManager); if (sessions == null) { sessions = new HashMap<>(); omemoSessions.put(omemoManager, sessions); } // Sessions with our own devices HashMap ourRawSessions = loadAllRawSessionsOf(omemoManager, omemoManager.getOwnJid()); ourRawSessions.remove(omemoManager.getDeviceId()); //Just to make sure we have no session with ourselves... sessions.putAll(createOmemoSessionsFromRawSessions(omemoManager, omemoManager.getOwnJid(), ourRawSessions)); // Sessions with contacts for (RosterEntry rosterEntry : Roster.getInstanceFor(omemoManager.getConnection()).getEntries()) { HashMap contactDevices = loadAllRawSessionsOf(omemoManager, rosterEntry.getJid().asBareJid()); sessions.putAll(createOmemoSessionsFromRawSessions(omemoManager, rosterEntry.getJid().asBareJid(), contactDevices)); } } /** * Forget all omemoSessions of the omemoManager from cache. * This will not remove the sessions from persistent memory! * * @param omemoManager omemoManager we want to forget sessions from. */ void forgetOmemoSessions(OmemoManager omemoManager) { omemoSessions.remove(omemoManager); } /** * Create a new concrete OmemoSession with a contact. * * @param omemoManager omemoManager of our device. * @param device device to establish the session with * @param identityKey identityKey of the device * @return concrete OmemoSession */ private OmemoSession createOmemoSession(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) { return keyUtil().createOmemoSession(omemoManager, this, device, identityKey); } /** * Return the OmemoSession for the OmemoDevice. If there is no OmemoSession for the device yet, * build one from local raw session material. * * @param omemoManager omemoManager of our device. * @param device OmemoDevice * @return OmemoSession */ public OmemoSession getOmemoSessionOf(OmemoManager omemoManager, OmemoDevice device) { HashMap> sessions = omemoSessions.get(omemoManager); if (sessions == null) { sessions = new HashMap<>(); omemoSessions.put(omemoManager, sessions); } OmemoSession session = sessions.get(device); // No OmemoSession found if (session == null) { T_IdKey identityKey = null; try { identityKey = loadOmemoIdentityKey(omemoManager, device); } catch (CorruptedOmemoKeyException e) { LOGGER.log(Level.WARNING, "getOmemoSessionOf could not load identityKey of " + device + ": " + e.getMessage()); } if (identityKey != null) { session = createOmemoSession(omemoManager, device, identityKey); } else { LOGGER.log(Level.INFO, "getOmemoSessionOf couldn't find an identityKey for " + device + ". Initiate session without."); session = createOmemoSession(omemoManager, device, null); } sessions.put(device, session); } if (session.getIdentityKey() == null) { try { session.setIdentityKey(loadOmemoIdentityKey(omemoManager, device)); } catch (CorruptedOmemoKeyException e) { LOGGER.log(Level.WARNING, "Can't update IdentityKey of " + device + ": " + e.getMessage()); } } return session; } /** * Create OmemoSession objects for all T_Sess objects of the contact. * The T_Sess objects will be wrapped inside a OmemoSession for every device of the contact. * * @param omemoManager omemoManager of our device. * @param contact BareJid of the contact * @param rawSessions HashMap of Integers (deviceIds) and T_Sess sessions. * @return HashMap of OmemoContacts and OmemoSessions */ private HashMap> createOmemoSessionsFromRawSessions(OmemoManager omemoManager, BareJid contact, HashMap rawSessions) { HashMap> sessions = new HashMap<>(); for (Map.Entry sessionEntry : rawSessions.entrySet()) { OmemoDevice omemoDevice = new OmemoDevice(contact, sessionEntry.getKey()); try { T_IdKey identityKey = loadOmemoIdentityKey(omemoManager, omemoDevice); if (identityKey != null) { sessions.put(omemoDevice, createOmemoSession(omemoManager, omemoDevice, identityKey)); } else { LOGGER.log(Level.WARNING, "IdentityKey of " + omemoDevice + " is null. Is this even possible at this point?"); } } catch (CorruptedOmemoKeyException e1) { LOGGER.log(Level.WARNING, "buildOmemoSessionFor could not create a session for " + omemoDevice + ": " + e1.getMessage()); } } return sessions; } // *sigh* /** * Return the id of the last generated preKey. * This is used to generate new preKeys without preKeyId collisions. * * @param omemoManager omemoManager of our device. * @return id of the last preKey */ public abstract int loadLastPreKeyId(OmemoManager omemoManager); /** * Store the id of the last preKey we generated. * * @param omemoManager omemoManager of our device. * @param currentPreKeyId the id of the last generated PreKey */ public abstract void storeLastPreKeyId(OmemoManager omemoManager, int currentPreKeyId); /** * Generate a new IdentityKeyPair. We should always have only one pair and usually keep this for a long time. * * @return identityKeyPair */ public T_IdKeyPair generateOmemoIdentityKeyPair() { return keyUtil().generateOmemoIdentityKeyPair(); } /** * Load our identityKeyPair from storage. * * @param omemoManager omemoManager of our device. * @return identityKeyPair * @throws CorruptedOmemoKeyException Thrown, if the stored key is damaged (*hands up* not my fault!) */ public abstract T_IdKeyPair loadOmemoIdentityKeyPair(OmemoManager omemoManager) throws CorruptedOmemoKeyException; /** * Store our identityKeyPair in storage. It would be a cool feature, if the key could be stored in a encrypted * database or something similar. * * @param omemoManager omemoManager of our device. * @param identityKeyPair identityKeyPair */ public abstract void storeOmemoIdentityKeyPair(OmemoManager omemoManager, T_IdKeyPair identityKeyPair); /** * Load the public identityKey of the device. * * @param omemoManager omemoManager of our device. * @param device device * @return identityKey * @throws CorruptedOmemoKeyException when the key in question is corrupted and cant be deserialized. */ public abstract T_IdKey loadOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device) throws CorruptedOmemoKeyException; /** * Store the public identityKey of the device. * * @param omemoManager omemoManager of our device. * @param device device * @param key identityKey */ public abstract void storeOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device, T_IdKey key); /** * Decide, whether a identityKey of a device is trusted or not. * If you want to use this module, you should memorize, whether the user has trusted this key or not, since * the owner of the identityKey will be able to read sent messages when this method returned 'true' for their * identityKey. Either you let the user decide whether you trust a key every time you see a new key, or you * implement something like 'blind trust' (see https://gultsch.de/trust.html). * * @param omemoManager omemoManager of our device. * @param device Owner of the key * @param identityKey identityKey * @return true, if the user trusts the key and wants to send messages to it, otherwise false */ public boolean isTrustedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) { return isTrustedOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey)); } public abstract boolean isTrustedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint); /** * Did the user yet made a decision about whether to trust or distrust this device? * * @param omemoManager omemoManager of our device. * @param device device * @param identityKey IdentityKey * @return true, if the user either trusted or distrusted the device. Return false, if the user did not yet decide. */ public boolean isDecidedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) { return isDecidedOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey)); } public abstract boolean isDecidedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint); /** * Trust an OmemoIdentity. This involves marking the key as trusted. * * @param omemoManager omemoManager of our device. * @param device device * @param identityKey identityKey */ public void trustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) { trustOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey)); } public abstract void trustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint identityKeyFingerprint); /** * Distrust an OmemoIdentity. This involved marking the key as distrusted. * * @param omemoManager omemoManager of our device. * @param device device * @param identityKey identityKey */ public void distrustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) { distrustOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey)); } public abstract void distrustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint); /** * Set the date in millis of the last message that was received from device 'from' to 'date'. * * @param omemoManager omemoManager of our device. * @param from device in question * @param date date of the last received message */ public abstract void setDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from, Date date); /** * Set the date in millis of the last message that was received from device 'from' to now. * * @param omemoManager omemoManager of our device. * @param from device in question */ public void setDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from) { this.setDateOfLastReceivedMessage(omemoManager, from, new Date()); } /** * Return the date in millis of the last message that was received from device 'from'. * * @param omemoManager omemoManager of our device. * @param from device in question * @return date if existent as long, otherwise -1 */ public abstract Date getDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from); /** * Set the date in millis of the last time the signed preKey was renewed. * * @param omemoManager omemoManager of our device. * @param date date */ public abstract void setDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager, Date date); /** * Store the date of the last preKey renewal in the omemoStore. * * @param omemoManager omemoManager of our device. */ public void setDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager) { setDateOfLastSignedPreKeyRenewal(omemoManager, new Date()); } /** * Get the date in millis of the last time the signed preKey was renewed. * * @param omemoManager omemoManager of our device. * @return date if existent, otherwise null */ public abstract Date getDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager); /** * Generate 'count' new PreKeys beginning with id 'startId'. * These preKeys are published and can be used by contacts to establish sessions with us. * * @param startId start id * @param count how many keys do we want to generate * @return Map of new preKeys */ public HashMap generateOmemoPreKeys(int startId, int count) { return keyUtil().generateOmemoPreKeys(startId, count); } /** * Load the preKey with id 'preKeyId' from storage. * * @param omemoManager omemoManager of our device. * @param preKeyId id of the key to be loaded * @return loaded preKey */ public abstract T_PreKey loadOmemoPreKey(OmemoManager omemoManager, int preKeyId); /** * Store a PreKey in storage. * * @param omemoManager omemoManager of our device. * @param preKeyId id of the key * @param preKey key */ public abstract void storeOmemoPreKey(OmemoManager omemoManager, int preKeyId, T_PreKey preKey); /** * Store a whole bunch of preKeys. * * @param omemoManager omemoManager of our device. * @param preKeyHashMap HashMap of preKeys */ public void storeOmemoPreKeys(OmemoManager omemoManager, HashMap preKeyHashMap) { for (Map.Entry e : preKeyHashMap.entrySet()) { storeOmemoPreKey(omemoManager, e.getKey(), e.getValue()); } } /** * remove a preKey from storage. This is called, when a contact used one of our preKeys to establish a session * with us. * * @param omemoManager omemoManager of our device. * @param preKeyId id of the used key that will be deleted */ public abstract void removeOmemoPreKey(OmemoManager omemoManager, int preKeyId); /** * Return the id of the currently used signed preKey. * This is used to avoid collisions when generating a new signedPreKey. * * @param omemoManager omemoManager of our device. * @return id */ public abstract int loadCurrentSignedPreKeyId(OmemoManager omemoManager); /** * Store the id of the currently used signedPreKey. * * @param omemoManager omemoManager of our device. * @param currentSignedPreKeyId if of the signedPreKey that is currently in use */ public abstract void storeCurrentSignedPreKeyId(OmemoManager omemoManager, int currentSignedPreKeyId); /** * Return all our current OmemoPreKeys. * * @param omemoManager omemoManager of our device. * @return Map containing our preKeys */ public abstract HashMap loadOmemoPreKeys(OmemoManager omemoManager); /** * Return the signedPreKey with the id 'singedPreKeyId'. * * @param omemoManager omemoManager of our device. * @param signedPreKeyId id of the key * @return key */ public abstract T_SigPreKey loadOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId); /** * Load all our signed PreKeys. * * @param omemoManager omemoManager of our device. * @return HashMap of our singedPreKeys */ public abstract HashMap loadOmemoSignedPreKeys(OmemoManager omemoManager); /** * Generate a new signed preKey. * * @param identityKeyPair identityKeyPair used to sign the preKey * @param signedPreKeyId id that the preKey will have * @return signedPreKey * @throws CorruptedOmemoKeyException when something goes wrong */ public T_SigPreKey generateOmemoSignedPreKey(T_IdKeyPair identityKeyPair, int signedPreKeyId) throws CorruptedOmemoKeyException { return keyUtil().generateOmemoSignedPreKey(identityKeyPair, signedPreKeyId); } /** * Store a signedPreKey in storage. * * @param omemoManager omemoManager of our device. * @param signedPreKeyId id of the signedPreKey * @param signedPreKey the key itself */ public abstract void storeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId, T_SigPreKey signedPreKey); /** * Remove a signedPreKey from storage. * * @param omemoManager omemoManager of our device. * @param signedPreKeyId id of the key that will be removed */ public abstract void removeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId); /** * Load the crypto-lib specific session object of the device from storage. * * @param omemoManager omemoManager of our device. * @param device device whose session we want to load * @return crypto related session */ public abstract T_Sess loadRawSession(OmemoManager omemoManager, OmemoDevice device); /** * Load all crypto-lib specific session objects of contact 'contact'. * * @param omemoManager omemoManager of our device. * @param contact BareJid of the contact we want to get all sessions from * @return HashMap of deviceId and sessions of the contact */ public abstract HashMap loadAllRawSessionsOf(OmemoManager omemoManager, BareJid contact); /** * Store a crypto-lib specific session to storage. * * @param omemoManager omemoManager of our device. * @param device OmemoDevice whose session we want to store * @param session session */ public abstract void storeRawSession(OmemoManager omemoManager, OmemoDevice device, T_Sess session); /** * Remove a crypto-lib specific session from storage. * * @param omemoManager omemoManager of our device. * @param device device whose session we want to delete */ public abstract void removeRawSession(OmemoManager omemoManager, OmemoDevice device); /** * Remove all crypto-lib specific session of a contact. * * @param omemoManager omemoManager of our device. * @param contact BareJid of the contact */ public abstract void removeAllRawSessionsOf(OmemoManager omemoManager, BareJid contact); /** * Return true, if we have a session with the device, otherwise false. * Hint for Signal: Do not try 'return getSession() != null' since this will create a new session. * * @param omemoManager omemoManager of our device. * @param device device * @return true if we have session, otherwise false */ public abstract boolean containsRawSession(OmemoManager omemoManager, OmemoDevice device); /** * Load a list of deviceIds from contact 'contact' from the local cache. * * @param omemoManager omemoManager of our device. * @param contact contact we want to get the deviceList of * @return CachedDeviceList of the contact */ public abstract CachedDeviceList loadCachedDeviceList(OmemoManager omemoManager, BareJid contact); /** * Store the DeviceList of the contact in local storage. * See this as a cache. * * @param omemoManager omemoManager of our device. * @param contact Contact * @param deviceList list of the contacts devices' ids. */ public abstract void storeCachedDeviceList(OmemoManager omemoManager, BareJid contact, CachedDeviceList deviceList); /** * Delete this device's IdentityKey, PreKeys, SignedPreKeys and Sessions. * * @param omemoManager omemoManager of our device. */ public abstract void purgeOwnDeviceKeys(OmemoManager omemoManager); /** * Return a concrete KeyUtil object that we can use as a utility to create keys etc. * * @return KeyUtil object */ public abstract OmemoKeyUtil keyUtil(); /** * Return our identityKeys fingerprint. * * @param omemoManager omemoManager of our device. * @return fingerprint of our identityKeyPair */ public OmemoFingerprint getFingerprint(OmemoManager omemoManager) { try { return keyUtil().getFingerprint(keyUtil().identityKeyFromPair(loadOmemoIdentityKeyPair(omemoManager))); } catch (CorruptedOmemoKeyException e) { LOGGER.log(Level.WARNING, "getFingerprint failed due to corrupted identityKeyPair: " + e.getMessage()); return null; } } /** * Return the default deviceId for a user. * The defaultDeviceId will be used when the OmemoManager gets instantiated without passing a specific deviceId. * If no default id is set, return -1; * * @param user user * @return defaultDeviceId or -1 */ public abstract int getDefaultDeviceId(BareJid user); /** * Set the default deviceId of a user. * * @param user user * @param defaultDeviceId defaultDeviceId */ public abstract void setDefaultDeviceId(BareJid user, int defaultDeviceId); /** * Return the fingerprint of the given devices announced identityKey. * * @param omemoManager omemoManager of our device. * @param device device * @throws CannotEstablishOmemoSessionException if we cannot establish a session * @return fingerprint of the identityKey */ public OmemoFingerprint getFingerprint(OmemoManager omemoManager, OmemoDevice device) throws CannotEstablishOmemoSessionException { T_IdKey idKey; try { idKey = loadOmemoIdentityKey(omemoManager, device); if (idKey == null) { OmemoService.getInstance().buildSessionFromOmemoBundle(omemoManager, device, true); } idKey = loadOmemoIdentityKey(omemoManager, device); } catch (CorruptedOmemoKeyException e) { LOGGER.log(Level.WARNING, "getFingerprint failed due to corrupted identityKey: " + e.getMessage()); return null; } return keyUtil().getFingerprint(idKey); } }