package org.whispersystems.libaxolotl.util; import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.libaxolotl.IdentityKeyPair; import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.libaxolotl.ecc.Curve; import org.whispersystems.libaxolotl.ecc.ECKeyPair; import org.whispersystems.libaxolotl.state.PreKeyRecord; import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.LinkedList; import java.util.List; /** * Helper class for generating keys of different types. * * @author Moxie Marlinspike */ public class KeyHelper { private KeyHelper() {} /** * Generate an identity key pair. Clients should only do this once, * at install time. * * @return the generated IdentityKeyPair. */ public static IdentityKeyPair generateIdentityKeyPair() { ECKeyPair keyPair = Curve.generateKeyPair(); IdentityKey publicKey = new IdentityKey(keyPair.getPublicKey()); return new IdentityKeyPair(publicKey, keyPair.getPrivateKey()); } /** * Generate a registration ID. Clients should only do this once, * at install time. * * @param extendedRange By default (false), the generated registration * ID is sized to require the minimal possible protobuf * encoding overhead. Specify true if the caller needs * the full range of MAX_INT at the cost of slightly * higher encoding overhead. * @return the generated registration ID. */ public static int generateRegistrationId(boolean extendedRange) { try { SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); if (extendedRange) return secureRandom.nextInt(Integer.MAX_VALUE - 1) + 1; else return secureRandom.nextInt(16380) + 1; } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } } public static int getRandomSequence(int max) { try { return SecureRandom.getInstance("SHA1PRNG").nextInt(max); } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } } /** * Generate a list of PreKeys. Clients should do this at install time, and * subsequently any time the list of PreKeys stored on the server runs low. *

* PreKey IDs are shorts, so they will eventually be repeated. Clients should * store PreKeys in a circular buffer, so that they are repeated as infrequently * as possible. * * @param start The starting PreKey ID, inclusive. * @param count The number of PreKeys to generate. * @return the list of generated PreKeyRecords. */ public static List generatePreKeys(int start, int count) { List results = new LinkedList<>(); start--; for (int i=0;i