OmemoKeyUtil.java

  1. /**
  2.  *
  3.  * Copyright 2017 Paul Schaub
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.omemo.util;

  18. import java.io.IOException;
  19. import java.util.HashMap;
  20. import java.util.Map;
  21. import java.util.TreeMap;
  22. import java.util.logging.Level;
  23. import java.util.logging.Logger;

  24. import org.jivesoftware.smackx.omemo.element.OmemoBundleElement;
  25. import org.jivesoftware.smackx.omemo.exceptions.CorruptedOmemoKeyException;
  26. import org.jivesoftware.smackx.omemo.internal.OmemoDevice;
  27. import org.jivesoftware.smackx.omemo.trust.OmemoFingerprint;

  28. /**
  29.  * Class that is used to convert bytes to keys and vice versa.
  30.  *
  31.  * @param <T_IdKeyPair> IdentityKeyPair class
  32.  * @param <T_IdKey>     IdentityKey class
  33.  * @param <T_PreKey>    PreKey class
  34.  * @param <T_SigPreKey> SignedPreKey class
  35.  * @param <T_Sess>      Session class
  36.  * @param <T_ECPub>     Elliptic Curve PublicKey class
  37.  * @param <T_Bundle>    Bundle class
  38.  * @author Paul Schaub
  39.  */
  40. @SuppressWarnings("InconsistentCapitalization")
  41. public abstract class OmemoKeyUtil<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey, T_Sess, T_ECPub, T_Bundle> {
  42.     private static final Logger LOGGER = Logger.getLogger(OmemoKeyUtil.class.getName());

  43.     public final Bundle BUNDLE = new Bundle();

  44.     /**
  45.      * Bundle related methods.
  46.      */
  47.     public class Bundle {

  48.         /**
  49.          * Extract an IdentityKey from a OmemoBundleElement.
  50.          *
  51.          * @param bundle OmemoBundleElement
  52.          * @return identityKey of the bundle
  53.          *
  54.          * @throws CorruptedOmemoKeyException if the key is damaged/malformed
  55.          */
  56.         public T_IdKey identityKey(OmemoBundleElement bundle) throws CorruptedOmemoKeyException {
  57.             return identityKeyFromBytes(bundle.getIdentityKey());
  58.         }

  59.         /**
  60.          * Extract a signedPreKey from an OmemoBundleElement.
  61.          *
  62.          * @param bundle OmemoBundleElement
  63.          * @return signed preKey
  64.          *
  65.          * @throws CorruptedOmemoKeyException if the key is damaged/malformed
  66.          */
  67.         public T_ECPub signedPreKeyPublic(OmemoBundleElement bundle) throws CorruptedOmemoKeyException {
  68.             return signedPreKeyPublicFromBytes(bundle.getSignedPreKey());
  69.         }

  70.         /**
  71.          * Extract the id of the transported signedPreKey from the bundle.
  72.          *
  73.          * @param bundle OmemoBundleElement
  74.          * @return id of the signed preKey
  75.          */
  76.         public int signedPreKeyId(OmemoBundleElement bundle) {
  77.             return bundle.getSignedPreKeyId();
  78.         }

  79.         /**
  80.          * Extract the signature of the signedPreKey in the bundle as a byte array.
  81.          *
  82.          * @param bundle OmemoBundleElement
  83.          * @return signature on the signed preKey
  84.          */
  85.         public byte[] signedPreKeySignature(OmemoBundleElement bundle) {
  86.             return bundle.getSignedPreKeySignature();
  87.         }

  88.         /**
  89.          * Extract the preKey with id 'keyId' from the bundle.
  90.          *
  91.          * @param bundle OmemoBundleElement
  92.          * @param keyId  id of the preKey
  93.          * @return the preKey
  94.          *
  95.          * @throws CorruptedOmemoKeyException when the key cannot be parsed from bytes
  96.          */
  97.         public T_ECPub preKeyPublic(OmemoBundleElement bundle, int keyId) throws CorruptedOmemoKeyException {
  98.             return preKeyPublicFromBytes(bundle.getPreKey(keyId));
  99.         }

  100.         /**
  101.          * Break up the OmemoBundleElement into a list of crypto-lib specific bundles (T_PreKey).
  102.          * In case of the signal library, we break the OmemoBundleElement in ~100 PreKeyBundles (one for every transported
  103.          * preKey).
  104.          *
  105.          * @param bundle  OmemoBundleElement containing multiple PreKeys
  106.          * @param contact Contact that the bundle belongs to
  107.          * @return a HashMap with one T_Bundle per preKey and the preKeyId as key
  108.          *
  109.          * @throws CorruptedOmemoKeyException when one of the keys cannot be parsed
  110.          */
  111.         public HashMap<Integer, T_Bundle> bundles(OmemoBundleElement bundle, OmemoDevice contact) throws CorruptedOmemoKeyException {
  112.             HashMap<Integer, T_Bundle> bundles = new HashMap<>();
  113.             for (int deviceId : bundle.getPreKeys().keySet()) {
  114.                 try {
  115.                     bundles.put(deviceId, bundleFromOmemoBundle(bundle, contact, deviceId));
  116.                 } catch (CorruptedOmemoKeyException e) {
  117.                     LOGGER.log(Level.INFO, "Cannot parse PreKeyBundle: " + e.getMessage());
  118.                 }
  119.             }
  120.             if (bundles.size() == 0) {
  121.                 throw new CorruptedOmemoKeyException("Bundle contained no valid preKeys.");
  122.             }
  123.             return bundles;
  124.         }
  125.     }

  126.     /**
  127.      * Deserialize an identityKeyPair from a byte array.
  128.      *
  129.      * @param data byte array
  130.      * @return IdentityKeyPair (T_IdKeyPair)
  131.      *
  132.      * @throws CorruptedOmemoKeyException if the key is damaged of malformed
  133.      */
  134.     public abstract T_IdKeyPair identityKeyPairFromBytes(byte[] data) throws CorruptedOmemoKeyException;

  135.     /**
  136.      * Deserialize an identityKey from a byte array.
  137.      *
  138.      * @param data byte array
  139.      * @return identityKey (T_IdKey)
  140.      *
  141.      * @throws CorruptedOmemoKeyException if the key is damaged or malformed
  142.      */
  143.     public abstract T_IdKey identityKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException;

  144.     /**
  145.      * Serialize an identityKey into bytes.
  146.      *
  147.      * @param identityKey idKey
  148.      * @return byte array representation of the identity key.
  149.      */
  150.     public abstract byte[] identityKeyToBytes(T_IdKey identityKey);

  151.     /**
  152.      * Deserialize an elliptic curve public key from bytes.
  153.      *
  154.      * @param data bytes
  155.      * @return elliptic curve public key (T_ECPub)
  156.      *
  157.      * @throws CorruptedOmemoKeyException if the key is damaged or malformed
  158.      */
  159.     public abstract T_ECPub ellipticCurvePublicKeyFromBytes(byte[] data) throws CorruptedOmemoKeyException;

  160.     /**
  161.      * Deserialize a public preKey from bytes.
  162.      *
  163.      * @param data preKey as bytes
  164.      * @return deserialized preKey
  165.      *
  166.      * @throws CorruptedOmemoKeyException if the key is damaged or malformed
  167.      */
  168.     public T_ECPub preKeyPublicFromBytes(byte[] data) throws CorruptedOmemoKeyException {
  169.         return ellipticCurvePublicKeyFromBytes(data);
  170.     }

  171.     /**
  172.      * Serialize a preKey into a byte array.
  173.      *
  174.      * @param preKey preKey
  175.      * @return byte[]
  176.      */
  177.     public abstract byte[] preKeyToBytes(T_PreKey preKey);

  178.     /**
  179.      * Deserialize a preKey from a byte array.
  180.      *
  181.      * @param bytes byte array
  182.      * @return deserialized preKey
  183.      *
  184.      * @throws IOException when something goes wrong
  185.      */
  186.     public abstract T_PreKey preKeyFromBytes(byte[] bytes) throws IOException;

  187.     /**
  188.      * Generate 'count' new PreKeys beginning with id 'startId'.
  189.      * These preKeys are published and can be used by contacts to establish sessions with us.
  190.      *
  191.      * @param startId start id
  192.      * @param count   how many keys do we want to generate
  193.      * @return Map of new preKeys
  194.      */
  195.     public abstract TreeMap<Integer, T_PreKey> generateOmemoPreKeys(int startId, int count);

  196.     /**
  197.      * Generate a new signed preKey.
  198.      *
  199.      * @param identityKeyPair identityKeyPair used to sign the preKey
  200.      * @param signedPreKeyId  id that the preKey will have
  201.      * @return deserialized signed preKey
  202.      *
  203.      * @throws CorruptedOmemoKeyException when the identityKeyPair is invalid
  204.      */
  205.     public abstract T_SigPreKey generateOmemoSignedPreKey(T_IdKeyPair identityKeyPair, int signedPreKeyId) throws CorruptedOmemoKeyException;


  206.     /**
  207.      * Deserialize a public signedPreKey from bytes.
  208.      *
  209.      * @param data bytes
  210.      * @return deserialized signed preKey
  211.      *
  212.      * @throws CorruptedOmemoKeyException if the key is damaged or malformed
  213.      */
  214.     public T_ECPub signedPreKeyPublicFromBytes(byte[] data) throws CorruptedOmemoKeyException {
  215.         return ellipticCurvePublicKeyFromBytes(data);
  216.     }

  217.     /**
  218.      * Deserialize a signedPreKey from a byte array.
  219.      *
  220.      * @param data byte array
  221.      * @return deserialized signed preKey
  222.      *
  223.      * @throws IOException when something goes wrong
  224.      */
  225.     public abstract T_SigPreKey signedPreKeyFromBytes(byte[] data) throws IOException;

  226.     /**
  227.      * Serialize a signedPreKey into a byte array.
  228.      *
  229.      * @param sigPreKey signedPreKey
  230.      * @return byte array
  231.      */
  232.     public abstract byte[] signedPreKeyToBytes(T_SigPreKey sigPreKey);

  233.     /**
  234.      * Build a crypto-lib specific PreKeyBundle (T_Bundle) using a PreKey from the OmemoBundleElement 'bundle'.
  235.      * The PreKeyBundle will contain the identityKey, signedPreKey and signature, as well as a preKey
  236.      * from the OmemoBundleElement.
  237.      *
  238.      * @param bundle  OmemoBundleElement
  239.      * @param contact Contact that the bundle belongs to
  240.      * @param keyId   id of the preKey that will be selected from the OmemoBundleElement and that the PreKeyBundle will contain
  241.      * @return PreKeyBundle (T_PreKey)
  242.      *
  243.      * @throws CorruptedOmemoKeyException if some key is damaged or malformed
  244.      */
  245.     public abstract T_Bundle bundleFromOmemoBundle(OmemoBundleElement bundle, OmemoDevice contact, int keyId) throws CorruptedOmemoKeyException;

  246.     /**
  247.      * Extract the signature from a signedPreKey.
  248.      *
  249.      * @param signedPreKey signedPreKey
  250.      * @return signature as byte array
  251.      */
  252.     public abstract byte[] signedPreKeySignatureFromKey(T_SigPreKey signedPreKey);

  253.     /**
  254.      * Generate a new IdentityKeyPair. We should always have only one pair and usually keep this for a long time.
  255.      *
  256.      * @return deserialized identity key pair
  257.      */
  258.     public abstract T_IdKeyPair generateOmemoIdentityKeyPair();

  259.     /**
  260.      * return the id of the given signedPreKey.
  261.      *
  262.      * @param signedPreKey key
  263.      * @return id of the key
  264.      */
  265.     public abstract int signedPreKeyIdFromKey(T_SigPreKey signedPreKey);

  266.     /**
  267.      * serialize an identityKeyPair into bytes.
  268.      *
  269.      * @param identityKeyPair identityKeyPair
  270.      * @return byte array
  271.      */
  272.     public abstract byte[] identityKeyPairToBytes(T_IdKeyPair identityKeyPair);

  273.     /**
  274.      * Extract the public identityKey from an identityKeyPair.
  275.      *
  276.      * @param pair keyPair
  277.      * @return public key of the pair
  278.      */
  279.     public abstract T_IdKey identityKeyFromPair(T_IdKeyPair pair);

  280.     /**
  281.      * Prepare an identityKey for transport in an OmemoBundleElement (serialize it).
  282.      *
  283.      * @param identityKey identityKey that will be transported
  284.      * @return key as byte array
  285.      */
  286.     public abstract byte[] identityKeyForBundle(T_IdKey identityKey);

  287.     /**
  288.      * Prepare an elliptic curve preKey for transport in an OmemoBundleElement.
  289.      *
  290.      * @param preKey key
  291.      * @return key as byte array
  292.      */
  293.     public abstract byte[] preKeyPublicKeyForBundle(T_ECPub preKey);

  294.     /**
  295.      * Prepare a preKey for transport in an OmemoBundleElement.
  296.      *
  297.      * @param preKey preKey
  298.      * @return key as byte array
  299.      */
  300.     public abstract byte[] preKeyForBundle(T_PreKey preKey);

  301.     /**
  302.      * Prepare a whole bunche of preKeys for transport.
  303.      *
  304.      * @param preKeyHashMap HashMap of preKeys
  305.      * @return HashMap of byte arrays but with the same keyIds as key
  306.      */
  307.     public HashMap<Integer, byte[]> preKeyPublicKeysForBundle(TreeMap<Integer, T_PreKey> preKeyHashMap) {
  308.         HashMap<Integer, byte[]> out = new HashMap<>();
  309.         for (Map.Entry<Integer, T_PreKey> e : preKeyHashMap.entrySet()) {
  310.             out.put(e.getKey(), preKeyForBundle(e.getValue()));
  311.         }
  312.         return out;
  313.     }

  314.     /**
  315.      * Prepare a public signedPreKey for transport in a bundle.
  316.      *
  317.      * @param signedPreKey signedPreKey
  318.      * @return signedPreKey as byte array
  319.      */
  320.     public abstract byte[] signedPreKeyPublicForBundle(T_SigPreKey signedPreKey);

  321.     /**
  322.      * Return the fingerprint of an identityKey.
  323.      *
  324.      * @param identityKey identityKey
  325.      * @return fingerprint of the key
  326.      */
  327.     public abstract OmemoFingerprint getFingerprintOfIdentityKey(T_IdKey identityKey);

  328.     /**
  329.      * Returns the fingerprint of the public key of an identityKeyPair.
  330.      * @param identityKeyPair IdentityKeyPair.
  331.      * @return fingerprint of the public key.
  332.      */
  333.     public abstract OmemoFingerprint getFingerprintOfIdentityKeyPair(T_IdKeyPair identityKeyPair);

  334.     /**
  335.      * Deserialize a raw OMEMO Session from bytes.
  336.      *
  337.      * @param data bytes
  338.      * @return raw OMEMO Session
  339.      *
  340.      * @throws IOException when something goes wrong
  341.      */
  342.     public abstract T_Sess rawSessionFromBytes(byte[] data) throws IOException;

  343.     /**
  344.      * Serialize a raw OMEMO session into a byte array.
  345.      *
  346.      * @param session raw session
  347.      * @return byte array
  348.      */
  349.     public abstract byte[] rawSessionToBytes(T_Sess session);

  350.     /**
  351.      * Add integers modulo MAX_VALUE.
  352.      *
  353.      * @param value base integer
  354.      * @param added value that is added to the base value
  355.      * @return (value plus added) modulo Integer.MAX_VALUE
  356.      */
  357.     public static int addInBounds(int value, int added) {
  358.         int avail = Integer.MAX_VALUE - value;
  359.         if (avail < added) {
  360.             return added - avail;
  361.         } else {
  362.             return value + added;
  363.         }
  364.     }
  365. }