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