001/**
002 *
003 * Copyright 2017 Paul Schaub
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.omemo;
018
019import static org.jivesoftware.smackx.omemo.util.OmemoConstants.TARGET_PRE_KEY_COUNT;
020
021import java.util.Date;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.WeakHashMap;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028import org.jivesoftware.smack.roster.Roster;
029import org.jivesoftware.smack.roster.RosterEntry;
030
031import org.jivesoftware.smackx.omemo.element.OmemoBundleVAxolotlElement;
032import org.jivesoftware.smackx.omemo.element.OmemoDeviceListElement;
033import org.jivesoftware.smackx.omemo.exceptions.CannotEstablishOmemoSessionException;
034import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
035import org.jivesoftware.smackx.omemo.internal.CachedDeviceList;
036import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
037import org.jivesoftware.smackx.omemo.internal.OmemoSession;
038import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil;
039
040import org.jxmpp.jid.BareJid;
041
042/**
043 * Class that presents some methods that are used to load/generate/store keys and session data needed for OMEMO.
044 *
045 * @param <T_IdKeyPair> IdentityKeyPair class
046 * @param <T_IdKey>     IdentityKey class
047 * @param <T_PreKey>    PreKey class
048 * @param <T_SigPreKey> SignedPreKey class
049 * @param <T_Sess>      Session class
050 * @param <T_Addr>      Address class
051 * @param <T_ECPub>     Elliptic Curve PublicKey class
052 * @param <T_Bundle>    Bundle class
053 * @param <T_Ciph>      Cipher class
054 * @author Paul Schaub
055 */
056public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> {
057    private static final Logger LOGGER = Logger.getLogger(OmemoStore.class.getName());
058
059    private final WeakHashMap<OmemoManager, HashMap<OmemoDevice, OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>>>
060            omemoSessions = new WeakHashMap<>();
061
062    /**
063     * Create a new OmemoStore.
064     */
065    public OmemoStore() {
066
067    }
068
069    /**
070     * Return true if this is a fresh installation.
071     *
072     * @param omemoManager omemoManager of our device.
073     * @return true or false.
074     */
075    public abstract boolean isFreshInstallation(OmemoManager omemoManager);
076
077    /**
078     * Check, if our freshly generated deviceId is available (unique) in our deviceList.
079     *
080     * @param omemoManager  omemoManager of our device.
081     * @param id            our deviceId.
082     * @return true if list did not contain our id, else false
083     */
084    boolean isAvailableDeviceId(OmemoManager omemoManager, int id) {
085        LOGGER.log(Level.INFO, "Check if id " + id + " is available...");
086
087        // Lookup local cached device list
088        BareJid ownJid = omemoManager.getOwnJid();
089        CachedDeviceList cachedDeviceList = loadCachedDeviceList(omemoManager, ownJid);
090
091        if (cachedDeviceList == null) {
092            cachedDeviceList = new CachedDeviceList();
093        }
094        // Does the list already contain that id?
095        return !cachedDeviceList.contains(id);
096    }
097
098    /**
099     * Generate a new Identity (deviceId, identityKeys, preKeys...).
100     *
101     * @param omemoManager omemoManager of our device we want to regenerate.
102     * @throws CorruptedOmemoKeyException in case something goes wrong
103     */
104    void regenerate(OmemoManager omemoManager) throws CorruptedOmemoKeyException {
105        LOGGER.log(Level.INFO, "Regenerating with deviceId " + omemoManager.getDeviceId() + "...");
106        int nextPreKeyId = 1;
107        storeOmemoIdentityKeyPair(omemoManager, generateOmemoIdentityKeyPair());
108        storeOmemoPreKeys(omemoManager, generateOmemoPreKeys(nextPreKeyId, TARGET_PRE_KEY_COUNT));
109        storeLastPreKeyId(omemoManager, OmemoKeyUtil.addInBounds(nextPreKeyId, TARGET_PRE_KEY_COUNT));
110        storeCurrentSignedPreKeyId(omemoManager, -1); //Set back to no-value default
111        changeSignedPreKey(omemoManager);
112        initializeOmemoSessions(omemoManager);
113    }
114
115    /**
116     * Merge the received OmemoDeviceListElement with the one we already have. If we had none, the received one is saved.
117     *
118     * @param omemoManager omemoManager of our device.
119     * @param contact Contact we received the list from.
120     * @param list    List we received.
121     */
122    void mergeCachedDeviceList(OmemoManager omemoManager, BareJid contact, OmemoDeviceListElement list) {
123        CachedDeviceList cached = loadCachedDeviceList(omemoManager, contact);
124
125        if (cached == null) {
126            cached = new CachedDeviceList();
127        }
128
129        if (list != null) {
130            cached.merge(list.getDeviceIds());
131        }
132        storeCachedDeviceList(omemoManager, contact, cached);
133    }
134
135    /**
136     * Renew our singed preKey. This should be done once every 7-14 days.
137     * The old signed PreKey should be kept for around a month or so (look it up in the XEP).
138     *
139     * @param omemoManager omemoManager of our device.
140     * @throws CorruptedOmemoKeyException when our identityKey is invalid
141     */
142    void changeSignedPreKey(OmemoManager omemoManager) throws CorruptedOmemoKeyException {
143        int lastSignedPreKeyId = loadCurrentSignedPreKeyId(omemoManager);
144        if (lastSignedPreKeyId == -1) lastSignedPreKeyId = 0;
145        try {
146            T_SigPreKey newSignedPreKey = generateOmemoSignedPreKey(loadOmemoIdentityKeyPair(omemoManager), lastSignedPreKeyId + 1);
147            storeOmemoSignedPreKey(omemoManager, lastSignedPreKeyId + 1, newSignedPreKey);
148            storeCurrentSignedPreKeyId(omemoManager, lastSignedPreKeyId + 1);
149            setDateOfLastSignedPreKeyRenewal(omemoManager);
150            removeOldSignedPreKeys(omemoManager);
151
152        } catch (CorruptedOmemoKeyException e) {
153            LOGGER.log(Level.INFO, "Couldn't change SignedPreKey: " + e.getMessage());
154            throw e;
155        }
156    }
157
158    /**
159     * Remove the oldest signedPreKey until there are only MAX_NUMBER_OF_STORED_SIGNED_PREKEYS left.
160     *
161     * @param omemoManager omemoManager of our device.
162     */
163    private void removeOldSignedPreKeys(OmemoManager omemoManager) {
164        if (OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys() <= 0) {
165            return;
166        }
167
168        int currentId = loadCurrentSignedPreKeyId(omemoManager);
169        if (currentId == -1) currentId = 0;
170        HashMap<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(omemoManager);
171
172        for (int i : signedPreKeys.keySet()) {
173            if (i <= currentId - OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys()) {
174                LOGGER.log(Level.INFO, "Remove signedPreKey " + i + ".");
175                removeOmemoSignedPreKey(omemoManager, i);
176            }
177        }
178    }
179
180    /**
181     * Pack a OmemoBundleElement containing our key material.
182     * If we used up n preKeys since we last published our bundle, generate n new preKeys and add them to the bundle.
183     * We should always publish TARGET_PRE_KEY_COUNT keys.
184     *
185     * @param omemoManager omemoManager of our device.
186     * @return OmemoBundleElement
187     * @throws CorruptedOmemoKeyException when a key could not be loaded
188     */
189    OmemoBundleVAxolotlElement packOmemoBundle(OmemoManager omemoManager) throws CorruptedOmemoKeyException {
190        int currentSignedPreKeyId = loadCurrentSignedPreKeyId(omemoManager);
191        if (currentSignedPreKeyId == -1) currentSignedPreKeyId = 0;
192        T_SigPreKey currentSignedPreKey = loadOmemoSignedPreKey(omemoManager, currentSignedPreKeyId);
193        T_IdKeyPair identityKeyPair = loadOmemoIdentityKeyPair(omemoManager);
194
195        HashMap<Integer, T_PreKey> preKeys = loadOmemoPreKeys(omemoManager);
196        int newKeysCount = TARGET_PRE_KEY_COUNT - preKeys.size();
197
198        if (newKeysCount > 0) {
199            int lastPreKeyId = loadLastPreKeyId(omemoManager);
200            if (lastPreKeyId == -1) lastPreKeyId = 0;
201            HashMap<Integer, T_PreKey> newKeys = generateOmemoPreKeys(lastPreKeyId + 1, newKeysCount);
202            storeOmemoPreKeys(omemoManager, newKeys);
203            preKeys.putAll(newKeys);
204            storeLastPreKeyId(omemoManager, lastPreKeyId + newKeysCount);
205        }
206
207        return new OmemoBundleVAxolotlElement(
208                currentSignedPreKeyId,
209                keyUtil().signedPreKeyPublicForBundle(currentSignedPreKey),
210                keyUtil().signedPreKeySignatureFromKey(currentSignedPreKey),
211                keyUtil().identityKeyForBundle(keyUtil().identityKeyFromPair(identityKeyPair)),
212                keyUtil().preKeyPublisKeysForBundle(preKeys)
213        );
214    }
215
216    /**
217     * Preload all OMEMO sessions for our devices and our contacts from existing raw sessions.
218     *
219     * @param omemoManager omemoManager of our device.
220     */
221    void initializeOmemoSessions(OmemoManager omemoManager) {
222
223        // Get HashMap of our omemoSessions
224        HashMap<OmemoDevice, OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>>
225                sessions = omemoSessions.get(omemoManager);
226        if (sessions == null) {
227            sessions = new HashMap<>();
228            omemoSessions.put(omemoManager, sessions);
229        }
230
231        // Sessions with our own devices
232        HashMap<Integer, T_Sess> ourRawSessions = loadAllRawSessionsOf(omemoManager, omemoManager.getOwnJid());
233        ourRawSessions.remove(omemoManager.getDeviceId()); //Just to make sure we have no session with ourselves...
234        sessions.putAll(createOmemoSessionsFromRawSessions(omemoManager, omemoManager.getOwnJid(), ourRawSessions));
235
236        // Sessions with contacts
237        for (RosterEntry rosterEntry : Roster.getInstanceFor(omemoManager.getConnection()).getEntries()) {
238            HashMap<Integer, T_Sess> contactDevices = loadAllRawSessionsOf(omemoManager, rosterEntry.getJid().asBareJid());
239            sessions.putAll(createOmemoSessionsFromRawSessions(omemoManager, rosterEntry.getJid().asBareJid(), contactDevices));
240        }
241    }
242
243    /**
244     * Forget all omemoSessions of the omemoManager from cache.
245     * This will not remove the sessions from persistent memory!
246     *
247     * @param omemoManager omemoManager we want to forget sessions from.
248     */
249    void forgetOmemoSessions(OmemoManager omemoManager) {
250        omemoSessions.remove(omemoManager);
251    }
252
253    /**
254     * Create a new concrete OmemoSession with a contact.
255     *
256     * @param omemoManager omemoManager of our device.
257     * @param device      device to establish the session with
258     * @param identityKey identityKey of the device
259     * @return concrete OmemoSession
260     */
261    private OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>
262    createOmemoSession(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) {
263        return keyUtil().createOmemoSession(omemoManager, this, device, identityKey);
264    }
265
266    /**
267     * Return the OmemoSession for the OmemoDevice. If there is no OmemoSession for the device yet,
268     * build one from local raw session material.
269     *
270     * @param omemoManager omemoManager of our device.
271     * @param device OmemoDevice
272     * @return OmemoSession
273     */
274    public OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>
275    getOmemoSessionOf(OmemoManager omemoManager, OmemoDevice device) {
276
277        HashMap<OmemoDevice, OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>>
278                sessions = omemoSessions.get(omemoManager);
279
280        if (sessions == null) {
281            sessions = new HashMap<>();
282            omemoSessions.put(omemoManager, sessions);
283        }
284
285        OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>
286                session = sessions.get(device);
287        // No OmemoSession found
288        if (session == null) {
289            T_IdKey identityKey = null;
290            try {
291                identityKey = loadOmemoIdentityKey(omemoManager, device);
292            } catch (CorruptedOmemoKeyException e) {
293                LOGGER.log(Level.WARNING, "getOmemoSessionOf could not load identityKey of " + device + ": " + e.getMessage());
294            }
295
296            if (identityKey != null) {
297                session = createOmemoSession(omemoManager, device, identityKey);
298
299            } else {
300                LOGGER.log(Level.INFO, "getOmemoSessionOf couldn't find an identityKey for " + device
301                        + ". Initiate session without.");
302                session = createOmemoSession(omemoManager, device, null);
303            }
304
305            sessions.put(device, session);
306        }
307
308        if (session.getIdentityKey() == null) {
309            try {
310                session.setIdentityKey(loadOmemoIdentityKey(omemoManager, device));
311            } catch (CorruptedOmemoKeyException e) {
312                LOGGER.log(Level.WARNING, "Can't update IdentityKey of " + device + ": " + e.getMessage());
313            }
314        }
315        return session;
316    }
317
318    /**
319     * Create OmemoSession objects for all T_Sess objects of the contact.
320     * The T_Sess objects will be wrapped inside a OmemoSession for every device of the contact.
321     *
322     * @param omemoManager omemoManager of our device.
323     * @param contact     BareJid of the contact
324     * @param rawSessions HashMap of Integers (deviceIds) and T_Sess sessions.
325     * @return HashMap of OmemoContacts and OmemoSessions
326     */
327    private HashMap<OmemoDevice, OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>>
328    createOmemoSessionsFromRawSessions(OmemoManager omemoManager, BareJid contact, HashMap<Integer, T_Sess> rawSessions) {
329
330        HashMap<OmemoDevice, OmemoSession<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph>>
331                sessions = new HashMap<>();
332
333        for (Map.Entry<Integer, T_Sess> sessionEntry : rawSessions.entrySet()) {
334            OmemoDevice omemoDevice = new OmemoDevice(contact, sessionEntry.getKey());
335            try {
336                T_IdKey identityKey = loadOmemoIdentityKey(omemoManager, omemoDevice);
337                if (identityKey != null) {
338                    sessions.put(omemoDevice, createOmemoSession(omemoManager, omemoDevice, identityKey));
339                } else {
340                    LOGGER.log(Level.WARNING, "IdentityKey of " + omemoDevice + " is null. Is this even possible at this point?");
341                }
342            } catch (CorruptedOmemoKeyException e1) {
343                LOGGER.log(Level.WARNING, "buildOmemoSessionFor could not create a session for " + omemoDevice +
344                        ": " + e1.getMessage());
345            }
346        }
347        return sessions;
348    }
349
350    // *sigh*
351
352    /**
353     * Return the id of the last generated preKey.
354     * This is used to generate new preKeys without preKeyId collisions.
355     *
356     * @param omemoManager omemoManager of our device.
357     * @return id of the last preKey
358     */
359    public abstract int loadLastPreKeyId(OmemoManager omemoManager);
360
361    /**
362     * Store the id of the last preKey we generated.
363     *
364     * @param omemoManager omemoManager of our device.
365     * @param currentPreKeyId the id of the last generated PreKey
366     */
367    public abstract void storeLastPreKeyId(OmemoManager omemoManager, int currentPreKeyId);
368
369    /**
370     * Generate a new IdentityKeyPair. We should always have only one pair and usually keep this for a long time.
371     *
372     * @return identityKeyPair
373     */
374    public T_IdKeyPair generateOmemoIdentityKeyPair() {
375        return keyUtil().generateOmemoIdentityKeyPair();
376    }
377
378    /**
379     * Load our identityKeyPair from storage.
380     *
381     * @param omemoManager omemoManager of our device.
382     * @return identityKeyPair
383     * @throws CorruptedOmemoKeyException Thrown, if the stored key is damaged (*hands up* not my fault!)
384     */
385    public abstract T_IdKeyPair loadOmemoIdentityKeyPair(OmemoManager omemoManager) throws CorruptedOmemoKeyException;
386
387    /**
388     * Store our identityKeyPair in storage. It would be a cool feature, if the key could be stored in a encrypted
389     * database or something similar.
390     *
391     * @param omemoManager omemoManager of our device.
392     * @param identityKeyPair identityKeyPair
393     */
394    public abstract void storeOmemoIdentityKeyPair(OmemoManager omemoManager, T_IdKeyPair identityKeyPair);
395
396    /**
397     * Load the public identityKey of the device.
398     *
399     * @param omemoManager omemoManager of our device.
400     * @param device device
401     * @return identityKey
402     * @throws CorruptedOmemoKeyException when the key in question is corrupted and cant be deserialized.
403     */
404    public abstract T_IdKey loadOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device) throws CorruptedOmemoKeyException;
405
406    /**
407     * Store the public identityKey of the device.
408     *
409     * @param omemoManager omemoManager of our device.
410     * @param device device
411     * @param key    identityKey
412     */
413    public abstract void storeOmemoIdentityKey(OmemoManager omemoManager, OmemoDevice device, T_IdKey key);
414
415    /**
416     * Decide, whether a identityKey of a device is trusted or not.
417     * If you want to use this module, you should memorize, whether the user has trusted this key or not, since
418     * the owner of the identityKey will be able to read sent messages when this method returned 'true' for their
419     * identityKey. Either you let the user decide whether you trust a key every time you see a new key, or you
420     * implement something like 'blind trust' (see https://gultsch.de/trust.html).
421     *
422     * @param omemoManager omemoManager of our device.
423     * @param device      Owner of the key
424     * @param identityKey identityKey
425     * @return true, if the user trusts the key and wants to send messages to it, otherwise false
426     */
427    public boolean isTrustedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) {
428        return isTrustedOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey));
429    }
430
431    public abstract boolean isTrustedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint);
432
433    /**
434     * Did the user yet made a decision about whether to trust or distrust this device?
435     *
436     * @param omemoManager omemoManager of our device.
437     * @param device      device
438     * @param identityKey IdentityKey
439     * @return true, if the user either trusted or distrusted the device. Return false, if the user did not yet decide.
440     */
441    public boolean isDecidedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) {
442        return isDecidedOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey));
443    }
444
445    public abstract boolean isDecidedOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint);
446
447    /**
448     * Trust an OmemoIdentity. This involves marking the key as trusted.
449     *
450     * @param omemoManager omemoManager of our device.
451     * @param device      device
452     * @param identityKey identityKey
453     */
454    public void trustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) {
455        trustOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey));
456    }
457
458    public abstract void trustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint identityKeyFingerprint);
459
460    /**
461     * Distrust an OmemoIdentity. This involved marking the key as distrusted.
462     *
463     * @param omemoManager omemoManager of our device.
464     * @param device      device
465     * @param identityKey identityKey
466     */
467    public void distrustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, T_IdKey identityKey) {
468        distrustOmemoIdentity(omemoManager, device, keyUtil().getFingerprint(identityKey));
469    }
470
471    public abstract void distrustOmemoIdentity(OmemoManager omemoManager, OmemoDevice device, OmemoFingerprint fingerprint);
472
473    /**
474     * Set the date in millis of the last message that was received from device 'from' to 'date'.
475     *
476     * @param omemoManager omemoManager of our device.
477     * @param from device in question
478     * @param date date of the last received message
479     */
480    public abstract void setDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from, Date date);
481
482    /**
483     * Set the date in millis of the last message that was received from device 'from' to now.
484     *
485     * @param omemoManager omemoManager of our device.
486     * @param from device in question
487     */
488    public void setDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from) {
489        this.setDateOfLastReceivedMessage(omemoManager, from, new Date());
490    }
491
492    /**
493     * Return the date in millis of the last message that was received from device 'from'.
494     *
495     * @param omemoManager omemoManager of our device.
496     * @param from device in question
497     * @return date if existent as long, otherwise -1
498     */
499    public abstract Date getDateOfLastReceivedMessage(OmemoManager omemoManager, OmemoDevice from);
500
501    /**
502     * Set the date in millis of the last time the signed preKey was renewed.
503     *
504     * @param omemoManager omemoManager of our device.
505     * @param date date
506     */
507    public abstract void setDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager, Date date);
508
509    /**
510     * Store the date of the last preKey renewal in the omemoStore.
511     *
512     * @param omemoManager omemoManager of our device.
513     */
514    public void setDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager) {
515        setDateOfLastSignedPreKeyRenewal(omemoManager, new Date());
516    }
517
518    /**
519     * Get the date in millis of the last time the signed preKey was renewed.
520     *
521     * @param omemoManager omemoManager of our device.
522     * @return date if existent, otherwise null
523     */
524    public abstract Date getDateOfLastSignedPreKeyRenewal(OmemoManager omemoManager);
525
526    /**
527     * Generate 'count' new PreKeys beginning with id 'startId'.
528     * These preKeys are published and can be used by contacts to establish sessions with us.
529     *
530     * @param startId start id
531     * @param count   how many keys do we want to generate
532     * @return Map of new preKeys
533     */
534    public HashMap<Integer, T_PreKey> generateOmemoPreKeys(int startId, int count) {
535        return keyUtil().generateOmemoPreKeys(startId, count);
536    }
537
538    /**
539     * Load the preKey with id 'preKeyId' from storage.
540     *
541     * @param omemoManager omemoManager of our device.
542     * @param preKeyId id of the key to be loaded
543     * @return loaded preKey
544     */
545    public abstract T_PreKey loadOmemoPreKey(OmemoManager omemoManager, int preKeyId);
546
547    /**
548     * Store a PreKey in storage.
549     *
550     * @param omemoManager omemoManager of our device.
551     * @param preKeyId id of the key
552     * @param preKey   key
553     */
554    public abstract void storeOmemoPreKey(OmemoManager omemoManager, int preKeyId, T_PreKey preKey);
555
556    /**
557     * Store a whole bunch of preKeys.
558     *
559     * @param omemoManager omemoManager of our device.
560     * @param preKeyHashMap HashMap of preKeys
561     */
562    public void storeOmemoPreKeys(OmemoManager omemoManager, HashMap<Integer, T_PreKey> preKeyHashMap) {
563        for (Map.Entry<Integer, T_PreKey> e : preKeyHashMap.entrySet()) {
564            storeOmemoPreKey(omemoManager, e.getKey(), e.getValue());
565        }
566    }
567
568    /**
569     * remove a preKey from storage. This is called, when a contact used one of our preKeys to establish a session
570     * with us.
571     *
572     * @param omemoManager omemoManager of our device.
573     * @param preKeyId id of the used key that will be deleted
574     */
575    public abstract void removeOmemoPreKey(OmemoManager omemoManager, int preKeyId);
576
577    /**
578     * Return the id of the currently used signed preKey.
579     * This is used to avoid collisions when generating a new signedPreKey.
580     *
581     * @param omemoManager omemoManager of our device.
582     * @return id
583     */
584    public abstract int loadCurrentSignedPreKeyId(OmemoManager omemoManager);
585
586    /**
587     * Store the id of the currently used signedPreKey.
588     *
589     * @param omemoManager omemoManager of our device.
590     * @param currentSignedPreKeyId if of the signedPreKey that is currently in use
591     */
592    public abstract void storeCurrentSignedPreKeyId(OmemoManager omemoManager, int currentSignedPreKeyId);
593
594    /**
595     * Return all our current OmemoPreKeys.
596     *
597     * @param omemoManager omemoManager of our device.
598     * @return Map containing our preKeys
599     */
600    public abstract HashMap<Integer, T_PreKey> loadOmemoPreKeys(OmemoManager omemoManager);
601
602    /**
603     * Return the signedPreKey with the id 'singedPreKeyId'.
604     *
605     * @param omemoManager omemoManager of our device.
606     * @param signedPreKeyId id of the key
607     * @return key
608     */
609    public abstract T_SigPreKey loadOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId);
610
611    /**
612     * Load all our signed PreKeys.
613     *
614     * @param omemoManager omemoManager of our device.
615     * @return HashMap of our singedPreKeys
616     */
617    public abstract HashMap<Integer, T_SigPreKey> loadOmemoSignedPreKeys(OmemoManager omemoManager);
618
619    /**
620     * Generate a new signed preKey.
621     *
622     * @param identityKeyPair identityKeyPair used to sign the preKey
623     * @param signedPreKeyId  id that the preKey will have
624     * @return signedPreKey
625     * @throws CorruptedOmemoKeyException when something goes wrong
626     */
627    public T_SigPreKey generateOmemoSignedPreKey(T_IdKeyPair identityKeyPair, int signedPreKeyId) throws CorruptedOmemoKeyException {
628        return keyUtil().generateOmemoSignedPreKey(identityKeyPair, signedPreKeyId);
629    }
630
631    /**
632     * Store a signedPreKey in storage.
633     *
634     * @param omemoManager omemoManager of our device.
635     * @param signedPreKeyId id of the signedPreKey
636     * @param signedPreKey   the key itself
637     */
638    public abstract void storeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId, T_SigPreKey signedPreKey);
639
640    /**
641     * Remove a signedPreKey from storage.
642     *
643     * @param omemoManager omemoManager of our device.
644     * @param signedPreKeyId id of the key that will be removed
645     */
646    public abstract void removeOmemoSignedPreKey(OmemoManager omemoManager, int signedPreKeyId);
647
648    /**
649     * Load the crypto-lib specific session object of the device from storage.
650     *
651     * @param omemoManager omemoManager of our device.
652     * @param device device whose session we want to load
653     * @return crypto related session
654     */
655    public abstract T_Sess loadRawSession(OmemoManager omemoManager, OmemoDevice device);
656
657    /**
658     * Load all crypto-lib specific session objects of contact 'contact'.
659     *
660     * @param omemoManager omemoManager of our device.
661     * @param contact BareJid of the contact we want to get all sessions from
662     * @return HashMap of deviceId and sessions of the contact
663     */
664    public abstract HashMap<Integer, T_Sess> loadAllRawSessionsOf(OmemoManager omemoManager, BareJid contact);
665
666    /**
667     * Store a crypto-lib specific session to storage.
668     *
669     * @param omemoManager omemoManager of our device.
670     * @param device  OmemoDevice whose session we want to store
671     * @param session session
672     */
673    public abstract void storeRawSession(OmemoManager omemoManager, OmemoDevice device, T_Sess session);
674
675    /**
676     * Remove a crypto-lib specific session from storage.
677     *
678     * @param omemoManager omemoManager of our device.
679     * @param device device whose session we want to delete
680     */
681    public abstract void removeRawSession(OmemoManager omemoManager, OmemoDevice device);
682
683    /**
684     * Remove all crypto-lib specific session of a contact.
685     *
686     * @param omemoManager omemoManager of our device.
687     * @param contact BareJid of the contact
688     */
689    public abstract void removeAllRawSessionsOf(OmemoManager omemoManager, BareJid contact);
690
691    /**
692     * Return true, if we have a session with the device, otherwise false.
693     * Hint for Signal: Do not try 'return getSession() != null' since this will create a new session.
694     *
695     * @param omemoManager omemoManager of our device.
696     * @param device device
697     * @return true if we have session, otherwise false
698     */
699    public abstract boolean containsRawSession(OmemoManager omemoManager, OmemoDevice device);
700
701    /**
702     * Load a list of deviceIds from contact 'contact' from the local cache.
703     *
704     * @param omemoManager omemoManager of our device.
705     * @param contact contact we want to get the deviceList of
706     * @return CachedDeviceList of the contact
707     */
708    public abstract CachedDeviceList loadCachedDeviceList(OmemoManager omemoManager, BareJid contact);
709
710    /**
711     * Store the DeviceList of the contact in local storage.
712     * See this as a cache.
713     *
714     * @param omemoManager omemoManager of our device.
715     * @param contact    Contact
716     * @param deviceList list of the contacts devices' ids.
717     */
718    public abstract void storeCachedDeviceList(OmemoManager omemoManager, BareJid contact, CachedDeviceList deviceList);
719
720    /**
721     * Delete this device's IdentityKey, PreKeys, SignedPreKeys and Sessions.
722     *
723     * @param omemoManager omemoManager of our device.
724     */
725    public abstract void purgeOwnDeviceKeys(OmemoManager omemoManager);
726
727    /**
728     * Return a concrete KeyUtil object that we can use as a utility to create keys etc.
729     *
730     * @return KeyUtil object
731     */
732    public abstract OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> keyUtil();
733
734    /**
735     * Return our identityKeys fingerprint.
736     *
737     * @param omemoManager omemoManager of our device.
738     * @return fingerprint of our identityKeyPair
739     */
740    public OmemoFingerprint getFingerprint(OmemoManager omemoManager) {
741        try {
742            return keyUtil().getFingerprint(keyUtil().identityKeyFromPair(loadOmemoIdentityKeyPair(omemoManager)));
743
744        } catch (CorruptedOmemoKeyException e) {
745            LOGGER.log(Level.WARNING, "getFingerprint failed due to corrupted identityKeyPair: " + e.getMessage());
746            return null;
747        }
748    }
749
750    /**
751     * Return the default deviceId for a user.
752     * The defaultDeviceId will be used when the OmemoManager gets instantiated without passing a specific deviceId.
753     * If no default id is set, return -1;
754     *
755     * @param user user
756     * @return defaultDeviceId or -1
757     */
758    public abstract int getDefaultDeviceId(BareJid user);
759
760    /**
761     * Set the default deviceId of a user.
762     *
763     * @param user user
764     * @param defaultDeviceId defaultDeviceId
765     */
766    public abstract void setDefaultDeviceId(BareJid user, int defaultDeviceId);
767
768    /**
769     * Return the fingerprint of the given devices announced identityKey.
770     *
771     * @param omemoManager omemoManager of our device.
772     * @param device device
773     * @throws CannotEstablishOmemoSessionException if we cannot establish a session
774     * @return fingerprint of the identityKey
775     */
776    public OmemoFingerprint getFingerprint(OmemoManager omemoManager, OmemoDevice device) throws CannotEstablishOmemoSessionException {
777        T_IdKey idKey;
778
779        try {
780            idKey = loadOmemoIdentityKey(omemoManager, device);
781            if (idKey == null) {
782                OmemoService.getInstance().buildSessionFromOmemoBundle(omemoManager, device, true);
783            }
784            idKey = loadOmemoIdentityKey(omemoManager, device);
785        } catch (CorruptedOmemoKeyException e) {
786            LOGGER.log(Level.WARNING, "getFingerprint failed due to corrupted identityKey: " + e.getMessage());
787            return null;
788        }
789        return keyUtil().getFingerprint(idKey);
790    }
791}