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.PRE_KEY_COUNT_PER_BUNDLE; 020 021import java.io.IOException; 022import java.util.Date; 023import java.util.Map; 024import java.util.SortedSet; 025import java.util.TreeMap; 026import java.util.logging.Level; 027import java.util.logging.Logger; 028 029import org.jivesoftware.smack.SmackException; 030 031import org.jivesoftware.smackx.omemo.element.OmemoBundleElement_VAxolotl; 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.exceptions.NoIdentityKeyException; 036import org.jivesoftware.smackx.omemo.internal.OmemoCachedDeviceList; 037import org.jivesoftware.smackx.omemo.internal.OmemoDevice; 038import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint; 039import org.jivesoftware.smackx.omemo.util.OmemoKeyUtil; 040 041import org.jxmpp.jid.BareJid; 042 043/** 044 * Class that presents some methods that are used to load/generate/store keys and session data needed for OMEMO. 045 * 046 * @param <T_IdKeyPair> IdentityKeyPair class 047 * @param <T_IdKey> IdentityKey class 048 * @param <T_PreKey> PreKey class 049 * @param <T_SigPreKey> SignedPreKey class 050 * @param <T_Sess> Session class 051 * @param <T_Addr> Address class 052 * @param <T_ECPub> Elliptic Curve PublicKey class 053 * @param <T_Bundle> Bundle class 054 * @param <T_Ciph> Cipher class 055 * 056 * @author Paul Schaub 057 */ 058public abstract class OmemoStore<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_Addr, T_ECPub, T_Bundle, T_Ciph> { 059 private static final Logger LOGGER = Logger.getLogger(OmemoStore.class.getName()); 060 061 /** 062 * Create a new OmemoStore. 063 */ 064 public OmemoStore() { 065 066 } 067 068 /** 069 * Returns a sorted set of all the deviceIds, the localUser has had data stored under in the store. 070 * Basically this returns the deviceIds of all "accounts" of localUser, which are known to the store. 071 * 072 * @param localUser BareJid of the user. 073 * @return set of deviceIds with available data. 074 */ 075 public abstract SortedSet<Integer> localDeviceIdsOf(BareJid localUser); 076 077 /** 078 * Check, if our freshly generated deviceId is available (unique) in our deviceList. 079 * 080 * @param userDevice our current device. 081 * @param id deviceId to check for. 082 * @return true if list did not contain our id, else false 083 * 084 * @throws IOException if an I/O error occurred. 085 */ 086 boolean isAvailableDeviceId(OmemoDevice userDevice, int id) throws IOException { 087 LOGGER.log(Level.INFO, "Check if id " + id + " is available..."); 088 089 // Lookup local cached device list 090 BareJid ownJid = userDevice.getJid(); 091 OmemoCachedDeviceList cachedDeviceList; 092 093 cachedDeviceList = loadCachedDeviceList(userDevice, ownJid); 094 095 if (cachedDeviceList == null) { 096 cachedDeviceList = new OmemoCachedDeviceList(); 097 } 098 // Does the list already contain that id? 099 return !cachedDeviceList.contains(id); 100 } 101 102 /** 103 * Merge the received OmemoDeviceListElement with the one we already have. If we had none, the received one is saved. 104 * 105 * @param userDevice our OmemoDevice. 106 * @param contact Contact we received the list from. 107 * @param list List we received. 108 * 109 * @throws IOException if an I/O error occurred. 110 */ 111 @SuppressWarnings("JavaUtilDate") 112 OmemoCachedDeviceList mergeCachedDeviceList(OmemoDevice userDevice, BareJid contact, OmemoDeviceListElement list) throws IOException { 113 OmemoCachedDeviceList cached = loadCachedDeviceList(userDevice, contact); 114 115 if (cached == null) { 116 cached = new OmemoCachedDeviceList(); 117 } 118 119 if (list == null) { 120 return cached; 121 } 122 123 for (int devId : list.getDeviceIds()) { 124 if (!cached.contains(devId)) { 125 setDateOfLastDeviceIdPublication(userDevice, new OmemoDevice(contact, devId), new Date()); 126 } 127 } 128 129 cached.merge(list.getDeviceIds()); 130 storeCachedDeviceList(userDevice, contact, cached); 131 132 return 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 userDevice our OmemoDevice. 140 * 141 * @throws CorruptedOmemoKeyException when our identityKey is invalid. 142 * @throws IOException if an I/O error occurred. 143 * @throws IllegalStateException when our IdentityKeyPair is null. 144 */ 145 @SuppressWarnings("JavaUtilDate") 146 void changeSignedPreKey(OmemoDevice userDevice) 147 throws CorruptedOmemoKeyException, IOException { 148 149 T_IdKeyPair idKeyPair = loadOmemoIdentityKeyPair(userDevice); 150 if (idKeyPair == null) { 151 throw new IllegalStateException("Our IdentityKeyPair is null."); 152 } 153 154 TreeMap<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(userDevice); 155 if (signedPreKeys.size() == 0) { 156 T_SigPreKey newKey = generateOmemoSignedPreKey(idKeyPair, 1); 157 storeOmemoSignedPreKey(userDevice, 1, newKey); 158 } else { 159 int lastId = signedPreKeys.lastKey(); 160 T_SigPreKey newKey = generateOmemoSignedPreKey(idKeyPair, lastId + 1); 161 storeOmemoSignedPreKey(userDevice, lastId + 1, newKey); 162 } 163 164 setDateOfLastSignedPreKeyRenewal(userDevice, new Date()); 165 removeOldSignedPreKeys(userDevice); 166 } 167 168 /** 169 * Remove the oldest signedPreKey until there are only MAX_NUMBER_OF_STORED_SIGNED_PREKEYS left. 170 * 171 * @param userDevice our OmemoDevice. 172 * 173 * @throws IOException if an I/O error occurred. 174 */ 175 private void removeOldSignedPreKeys(OmemoDevice userDevice) throws IOException { 176 if (OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys() <= 0) { 177 return; 178 } 179 180 TreeMap<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(userDevice); 181 182 for (int i = 0; i < signedPreKeys.keySet().size() - OmemoConfiguration.getMaxNumberOfStoredSignedPreKeys(); i++) { 183 int keyId = signedPreKeys.firstKey(); 184 LOGGER.log(Level.INFO, "Remove signedPreKey " + keyId + "."); 185 removeOmemoSignedPreKey(userDevice, i); 186 signedPreKeys = loadOmemoSignedPreKeys(userDevice); 187 } 188 } 189 190 /** 191 * Pack a OmemoBundleElement containing our key material. 192 * 193 * @param userDevice our OmemoDevice. 194 * @return OMEMO bundle element 195 * 196 * @throws CorruptedOmemoKeyException when a key could not be loaded 197 * @throws IOException if an I/O error occurred. 198 */ 199 OmemoBundleElement_VAxolotl packOmemoBundle(OmemoDevice userDevice) 200 throws CorruptedOmemoKeyException, IOException { 201 202 int currentSignedPreKeyId = loadCurrentOmemoSignedPreKeyId(userDevice); 203 T_SigPreKey currentSignedPreKey = loadOmemoSignedPreKeys(userDevice).get(currentSignedPreKeyId); 204 205 return new OmemoBundleElement_VAxolotl( 206 currentSignedPreKeyId, 207 keyUtil().signedPreKeyPublicForBundle(currentSignedPreKey), 208 keyUtil().signedPreKeySignatureFromKey(currentSignedPreKey), 209 keyUtil().identityKeyForBundle(keyUtil().identityKeyFromPair(loadOmemoIdentityKeyPair(userDevice))), 210 keyUtil().preKeyPublicKeysForBundle(loadOmemoPreKeys(userDevice)) 211 ); 212 } 213 214 /** 215 * Replenish our supply of keys. If we are missing any type of keys, generate them fresh. 216 * 217 * @param userDevice our own OMEMO device 218 * 219 * @throws CorruptedOmemoKeyException if the OMEMO key is corrupted. 220 * @throws IOException if an I/O error occurred. 221 */ 222 public void replenishKeys(OmemoDevice userDevice) 223 throws CorruptedOmemoKeyException, IOException { 224 225 T_IdKeyPair identityKeyPair = loadOmemoIdentityKeyPair(userDevice); 226 if (identityKeyPair == null) { 227 identityKeyPair = generateOmemoIdentityKeyPair(); 228 storeOmemoIdentityKeyPair(userDevice, identityKeyPair); 229 } 230 231 Map<Integer, T_SigPreKey> signedPreKeys = loadOmemoSignedPreKeys(userDevice); 232 if (signedPreKeys.size() == 0) { 233 changeSignedPreKey(userDevice); 234 } 235 236 TreeMap<Integer, T_PreKey> preKeys = loadOmemoPreKeys(userDevice); 237 int newKeysCount = PRE_KEY_COUNT_PER_BUNDLE - preKeys.size(); 238 int startId = preKeys.size() == 0 ? 0 : preKeys.lastKey(); 239 240 if (newKeysCount > 0) { 241 Map<Integer, T_PreKey> newKeys = generateOmemoPreKeys(startId + 1, newKeysCount); 242 storeOmemoPreKeys(userDevice, newKeys); 243 } 244 } 245 246 // *sigh* 247 248 /** 249 * Generate a new IdentityKeyPair. We should always have only one pair and usually keep this for a long time. 250 * 251 * @return a fresh identityKeyPair 252 */ 253 public T_IdKeyPair generateOmemoIdentityKeyPair() { 254 return keyUtil().generateOmemoIdentityKeyPair(); 255 } 256 257 /** 258 * Load our identityKeyPair from storage. 259 * Return null, if we have no identityKeyPair. 260 * 261 * @param userDevice our OmemoDevice. 262 * @return loaded identityKeyPair 263 * 264 * @throws CorruptedOmemoKeyException Thrown, if the stored key is damaged (*hands up* not my fault!) 265 * @throws IOException if an I/O error occurred. 266 */ 267 public abstract T_IdKeyPair loadOmemoIdentityKeyPair(OmemoDevice userDevice) 268 throws CorruptedOmemoKeyException, IOException; 269 270 /** 271 * Store our identityKeyPair in storage. It would be a cool feature, if the key could be stored in a encrypted 272 * database or something similar. 273 * 274 * @param userDevice our OmemoDevice. 275 * @param identityKeyPair identityKeyPair 276 * 277 * @throws IOException if an I/O error occurred. 278 */ 279 public abstract void storeOmemoIdentityKeyPair(OmemoDevice userDevice, T_IdKeyPair identityKeyPair) throws IOException; 280 281 /** 282 * Remove the identityKeyPair of a user. 283 * 284 * @param userDevice our device. 285 */ 286 public abstract void removeOmemoIdentityKeyPair(OmemoDevice userDevice); 287 288 /** 289 * Load the public identityKey of a device. 290 * 291 * @param userDevice our OmemoDevice. 292 * @param contactsDevice the device of which we want to load the identityKey. 293 * @return loaded identityKey 294 * 295 * @throws CorruptedOmemoKeyException when the key in question is corrupted and cant be deserialized. 296 * @throws IOException if an I/O error occurred. 297 */ 298 public abstract T_IdKey loadOmemoIdentityKey(OmemoDevice userDevice, OmemoDevice contactsDevice) 299 throws CorruptedOmemoKeyException, IOException; 300 301 /** 302 * Store the public identityKey of the device. 303 * 304 * @param userDevice our OmemoDevice. 305 * @param contactsDevice device. 306 * @param contactsKey identityKey belonging to the contactsDevice. 307 * 308 * @throws IOException if an I/O error occurred. 309 */ 310 public abstract void storeOmemoIdentityKey(OmemoDevice userDevice, OmemoDevice contactsDevice, T_IdKey contactsKey) throws IOException; 311 312 /** 313 * Removes the identityKey of a device. 314 * 315 * @param userDevice our omemoDevice. 316 * @param contactsDevice device of which we want to delete the identityKey. 317 */ 318 public abstract void removeOmemoIdentityKey(OmemoDevice userDevice, OmemoDevice contactsDevice); 319 320 /** 321 * Store the number of messages we sent to a device since we last received a message back. 322 * This counter gets reset to 0 whenever we receive a message from the contacts device. 323 * 324 * @param userDevice our omemoDevice. 325 * @param contactsDevice device of which we want to set the message counter. 326 * @param counter counter value. 327 * 328 * @throws IOException if an I/O error occurred. 329 */ 330 public abstract void storeOmemoMessageCounter(OmemoDevice userDevice, OmemoDevice contactsDevice, int counter) throws IOException; 331 332 /** 333 * Return the current value of the message counter. 334 * This counter represents the number of message we sent to the contactsDevice without getting a reply back. 335 * The default value for this counter is 0. 336 * 337 * @param userDevice our omemoDevice 338 * @param contactsDevice device of which we want to get the message counter. 339 * @return counter value. 340 * 341 * @throws IOException if an I/O error occurred. 342 */ 343 public abstract int loadOmemoMessageCounter(OmemoDevice userDevice, OmemoDevice contactsDevice) throws IOException; 344 345 /** 346 * Set the date of the last message that was received from a device. 347 * 348 * @param userDevice omemoManager of our device. 349 * @param contactsDevice device in question 350 * @param date date of the last received message 351 * 352 * @throws IOException if an I/O error occurred. 353 */ 354 public abstract void setDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) throws IOException; 355 356 /** 357 * Return the date of the last message that was received from device 'from'. 358 * 359 * @param userDevice our OmemoDevice. 360 * @param contactsDevice device in question 361 * @return date if existent, null 362 * 363 * @throws IOException if an I/O error occurred. 364 */ 365 public abstract Date getDateOfLastReceivedMessage(OmemoDevice userDevice, OmemoDevice contactsDevice) throws IOException; 366 367 /** 368 * Set the date of the last time the deviceId was published. This method only gets called, when the deviceId 369 * was inactive/non-existent before it was published. 370 * 371 * @param userDevice our OmemoDevice 372 * @param contactsDevice OmemoDevice in question 373 * @param date date of the last publication after not being published 374 * 375 * @throws IOException if an I/O error occurred. 376 */ 377 public abstract void setDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice, Date date) throws IOException; 378 379 /** 380 * Return the date of the last time the deviceId was published after previously being not published. 381 * (Point in time, where the status of the deviceId changed from inactive/non-existent to active). 382 * 383 * @param userDevice our OmemoDevice 384 * @param contactsDevice OmemoDevice in question 385 * @return date of the last publication after not being published 386 * 387 * @throws IOException if an I/O error occurred. 388 */ 389 public abstract Date getDateOfLastDeviceIdPublication(OmemoDevice userDevice, OmemoDevice contactsDevice) throws IOException; 390 391 /** 392 * Set the date of the last time the signed preKey was renewed. 393 * 394 * @param userDevice our OmemoDevice. 395 * @param date date 396 * 397 * @throws IOException if an I/O error occurred. 398 */ 399 public abstract void setDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice, Date date) throws IOException; 400 401 /** 402 * Get the date of the last time the signed preKey was renewed. 403 * 404 * @param userDevice our OmemoDevice. 405 * @return date if existent, otherwise null 406 * 407 * @throws IOException if an I/O error occurred. 408 */ 409 public abstract Date getDateOfLastSignedPreKeyRenewal(OmemoDevice userDevice) throws IOException; 410 411 /** 412 * Generate 'count' new PreKeys beginning with id 'startId'. 413 * These preKeys are published and can be used by contacts to establish sessions with us. 414 * 415 * @param startId start id 416 * @param count how many keys do we want to generate 417 * @return Map of new preKeys 418 */ 419 @SuppressWarnings("NonApiType") 420 public TreeMap<Integer, T_PreKey> generateOmemoPreKeys(int startId, int count) { 421 return keyUtil().generateOmemoPreKeys(startId, count); 422 } 423 424 /** 425 * Load the preKey with id 'preKeyId' from storage. 426 * 427 * @param userDevice our OmemoDevice. 428 * @param preKeyId id of the key to be loaded 429 * @return loaded preKey 430 * 431 * @throws IOException if an I/O error occurred. 432 */ 433 public abstract T_PreKey loadOmemoPreKey(OmemoDevice userDevice, int preKeyId) throws IOException; 434 435 /** 436 * Store a PreKey in storage. 437 * 438 * @param userDevice our OmemoDevice. 439 * @param preKeyId id of the key 440 * @param preKey key 441 * 442 * @throws IOException if an I/O error occurred. 443 */ 444 public abstract void storeOmemoPreKey(OmemoDevice userDevice, int preKeyId, T_PreKey preKey) throws IOException; 445 446 /** 447 * Store a whole bunch of preKeys. 448 * 449 * @param userDevice our OmemoDevice. 450 * @param preKeyHashMap HashMap of preKeys 451 * 452 * @throws IOException if an I/O error occurred. 453 */ 454 public void storeOmemoPreKeys(OmemoDevice userDevice, Map<Integer, T_PreKey> preKeyHashMap) throws IOException { 455 for (Map.Entry<Integer, T_PreKey> entry : preKeyHashMap.entrySet()) { 456 storeOmemoPreKey(userDevice, entry.getKey(), entry.getValue()); 457 } 458 } 459 460 /** 461 * Remove a preKey from storage. This is called, when a contact used one of our preKeys to establish a session 462 * with us. 463 * 464 * @param userDevice our OmemoDevice. 465 * @param preKeyId id of the used key that will be deleted 466 */ 467 public abstract void removeOmemoPreKey(OmemoDevice userDevice, int preKeyId); 468 469 /** 470 * Return all our current OmemoPreKeys. 471 * 472 * @param userDevice our OmemoDevice. 473 * @return Map containing our preKeys 474 * 475 * @throws IOException if an I/O error occurred. 476 */ 477 @SuppressWarnings("NonApiType") 478 public abstract TreeMap<Integer, T_PreKey> loadOmemoPreKeys(OmemoDevice userDevice) throws IOException; 479 480 /** 481 * Return the signedPreKey with the id 'singedPreKeyId'. 482 * 483 * @param userDevice our OmemoDevice. 484 * @param signedPreKeyId id of the key 485 * @return loaded signed preKey 486 * 487 * @throws IOException if an I/O error occurred. 488 */ 489 public abstract T_SigPreKey loadOmemoSignedPreKey(OmemoDevice userDevice, int signedPreKeyId) throws IOException; 490 491 public int loadCurrentOmemoSignedPreKeyId(OmemoDevice userDevice) throws IOException { 492 return loadOmemoSignedPreKeys(userDevice).lastKey(); 493 } 494 495 /** 496 * Load all our signed PreKeys. 497 * 498 * @param userDevice our OmemoDevice. 499 * @return HashMap of our singedPreKeys 500 * 501 * @throws IOException if an I/O error occurred. 502 */ 503 // TreeMap seems to be required for this function. 504 @SuppressWarnings("NonApiType") 505 public abstract TreeMap<Integer, T_SigPreKey> loadOmemoSignedPreKeys(OmemoDevice userDevice) throws IOException; 506 507 /** 508 * Generate a new signed preKey. 509 * 510 * @param identityKeyPair identityKeyPair used to sign the preKey 511 * @param signedPreKeyId id that the preKey will have 512 * @return a fresh signedPreKey 513 * 514 * @throws CorruptedOmemoKeyException when something goes wrong 515 */ 516 public T_SigPreKey generateOmemoSignedPreKey(T_IdKeyPair identityKeyPair, int signedPreKeyId) 517 throws CorruptedOmemoKeyException { 518 return keyUtil().generateOmemoSignedPreKey(identityKeyPair, signedPreKeyId); 519 } 520 521 /** 522 * Store a signedPreKey in storage. 523 * 524 * @param userDevice our OmemoDevice. 525 * @param signedPreKeyId id of the signedPreKey 526 * @param signedPreKey the key itself 527 * 528 * @throws IOException if an I/O error occurred. 529 */ 530 public abstract void storeOmemoSignedPreKey(OmemoDevice userDevice, int signedPreKeyId, T_SigPreKey signedPreKey) throws IOException; 531 532 /** 533 * Remove a signedPreKey from storage. 534 * 535 * @param userDevice our OmemoDevice. 536 * @param signedPreKeyId id of the key that will be removed 537 */ 538 public abstract void removeOmemoSignedPreKey(OmemoDevice userDevice, int signedPreKeyId); 539 540 /** 541 * Load the crypto-lib specific session object of the device from storage. 542 * 543 * @param userDevice our OmemoDevice. 544 * @param contactsDevice device whose session we want to load 545 * @return crypto related session 546 * 547 * @throws IOException if an I/O error occurred. 548 */ 549 public abstract T_Sess loadRawSession(OmemoDevice userDevice, OmemoDevice contactsDevice) throws IOException; 550 551 /** 552 * Load all crypto-lib specific session objects of contact 'contact'. 553 * 554 * @param userDevice our OmemoDevice. 555 * @param contact BareJid of the contact we want to get all sessions from 556 * @return TreeMap of deviceId and sessions of the contact 557 * 558 * @throws IOException if an I/O error occurred. 559 */ 560 public abstract Map<Integer, T_Sess> loadAllRawSessionsOf(OmemoDevice userDevice, BareJid contact) throws IOException; 561 562 /** 563 * Store a crypto-lib specific session to storage. 564 * 565 * @param userDevice our OmemoDevice. 566 * @param contactsDevice OmemoDevice whose session we want to store 567 * @param session session 568 * 569 * @throws IOException if an I/O error occurred. 570 */ 571 public abstract void storeRawSession(OmemoDevice userDevice, OmemoDevice contactsDevice, T_Sess session) throws IOException; 572 573 /** 574 * Remove a crypto-lib specific session from storage. 575 * 576 * @param userDevice our OmemoDevice. 577 * @param contactsDevice device whose session we want to delete 578 */ 579 public abstract void removeRawSession(OmemoDevice userDevice, OmemoDevice contactsDevice); 580 581 /** 582 * Remove all crypto-lib specific session of a contact. 583 * 584 * @param userDevice our OmemoDevice. 585 * @param contact BareJid of the contact 586 */ 587 public abstract void removeAllRawSessionsOf(OmemoDevice userDevice, BareJid contact); 588 589 /** 590 * Return true, if we have a session with the device, otherwise false. 591 * Hint for Signal: Do not try 'return getSession() != null' since this will create a new session. 592 * 593 * @param userDevice our OmemoDevice. 594 * @param contactsDevice device 595 * @return true if we have session, otherwise false 596 */ 597 public abstract boolean containsRawSession(OmemoDevice userDevice, OmemoDevice contactsDevice); 598 599 /** 600 * Load a list of deviceIds from contact 'contact' from the local cache. 601 * 602 * @param userDevice our OmemoDevice. 603 * @param contact contact we want to get the deviceList of 604 * @return CachedDeviceList of the contact 605 * 606 * @throws IOException if an I/O error occurred. 607 */ 608 public abstract OmemoCachedDeviceList loadCachedDeviceList(OmemoDevice userDevice, BareJid contact) throws IOException; 609 610 /** 611 * Load a list of deviceIds from our own devices. 612 * 613 * @param userDevice our own OMEMO device 614 * @return the cached OMEMO device list. 615 * 616 * @throws IOException if an I/O error occurred. 617 */ 618 public OmemoCachedDeviceList loadCachedDeviceList(OmemoDevice userDevice) throws IOException { 619 return loadCachedDeviceList(userDevice, userDevice.getJid()); 620 } 621 622 /** 623 * Store the DeviceList of the contact in local storage. 624 * See this as a cache. 625 * 626 * @param userDevice our OmemoDevice. 627 * @param contact Contact 628 * @param contactsDeviceList list of the contacts devices' ids. 629 * 630 * @throws IOException if an I/O error occurred. 631 */ 632 public abstract void storeCachedDeviceList(OmemoDevice userDevice, 633 BareJid contact, 634 OmemoCachedDeviceList contactsDeviceList) throws IOException; 635 636 /** 637 * Delete this device's IdentityKey, PreKeys, SignedPreKeys and Sessions. 638 * 639 * @param userDevice our OmemoDevice. 640 */ 641 public abstract void purgeOwnDeviceKeys(OmemoDevice userDevice); 642 643 /** 644 * Return a concrete KeyUtil object that we can use as a utility to create keys etc. 645 * 646 * @return KeyUtil object 647 */ 648 public abstract OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_ECPub, T_Bundle> keyUtil(); 649 650 /** 651 * Return our identityKeys fingerprint. 652 * 653 * @param userDevice our OmemoDevice. 654 * @return fingerprint of our identityKeyPair 655 * 656 * @throws CorruptedOmemoKeyException if the identityKey of userDevice is corrupted. 657 * @throws IOException if an I/O error occurred. 658 */ 659 public OmemoFingerprint getFingerprint(OmemoDevice userDevice) 660 throws CorruptedOmemoKeyException, IOException { 661 662 T_IdKeyPair keyPair = loadOmemoIdentityKeyPair(userDevice); 663 if (keyPair == null) { 664 return null; 665 } 666 667 return keyUtil().getFingerprintOfIdentityKey(keyUtil().identityKeyFromPair(keyPair)); 668 } 669 670 /** 671 * Return the fingerprint of the identityKey belonging to contactsDevice. 672 * 673 * @param userDevice our OmemoDevice. 674 * @param contactsDevice OmemoDevice we want to have the fingerprint for. 675 * @return fingerprint of the userDevices IdentityKey. 676 * 677 * @throws CorruptedOmemoKeyException if the IdentityKey is corrupted. 678 * @throws NoIdentityKeyException if no IdentityKey for contactsDevice has been found locally. 679 * @throws IOException if an I/O error occurred. 680 */ 681 public OmemoFingerprint getFingerprint(OmemoDevice userDevice, OmemoDevice contactsDevice) 682 throws CorruptedOmemoKeyException, NoIdentityKeyException, IOException { 683 684 T_IdKey identityKey = loadOmemoIdentityKey(userDevice, contactsDevice); 685 if (identityKey == null) { 686 throw new NoIdentityKeyException(contactsDevice); 687 } 688 return keyUtil().getFingerprintOfIdentityKey(identityKey); 689 } 690 691 /** 692 * Return the fingerprint of the given devices announced identityKey. 693 * If we have no local copy of the identityKey of the contact, build a fresh session in order to get the key. 694 * 695 * @param managerGuard authenticated OmemoManager 696 * @param contactsDevice OmemoDevice we want to get the fingerprint from 697 * @return fingerprint of the contacts OMEMO device 698 * 699 * @throws CannotEstablishOmemoSessionException If we have no local copy of the identityKey of the contact 700 * and are unable to build a fresh session 701 * @throws CorruptedOmemoKeyException If the identityKey we have of the contact is corrupted 702 * @throws SmackException.NotConnectedException if the XMPP connection is not connected. 703 * @throws InterruptedException if the calling thread was interrupted. 704 * @throws SmackException.NoResponseException if there was no response from the remote entity. 705 * @throws IOException if an I/O error occurred. 706 */ 707 public OmemoFingerprint getFingerprintAndMaybeBuildSession(OmemoManager.LoggedInOmemoManager managerGuard, OmemoDevice contactsDevice) 708 throws CannotEstablishOmemoSessionException, CorruptedOmemoKeyException, 709 SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException, IOException { 710 OmemoManager omemoManager = managerGuard.get(); 711 712 // Load identityKey 713 T_IdKey identityKey = loadOmemoIdentityKey(omemoManager.getOwnDevice(), contactsDevice); 714 if (identityKey == null) { 715 // Key cannot be loaded. Maybe it doesn't exist. Fetch a bundle to get it... 716 OmemoService.getInstance().buildFreshSessionWithDevice(omemoManager.getConnection(), 717 omemoManager.getOwnDevice(), contactsDevice); 718 } 719 720 // Load identityKey again 721 identityKey = loadOmemoIdentityKey(omemoManager.getOwnDevice(), contactsDevice); 722 if (identityKey == null) { 723 return null; 724 } 725 726 return keyUtil().getFingerprintOfIdentityKey(identityKey); 727 } 728}