package org.thoughtcrime.securesms.crypto; import android.content.Context; import android.util.Log; import com.google.protobuf.ByteString; import org.thoughtcrime.securesms.database.keys.InvalidKeyIdException; import org.thoughtcrime.securesms.database.keys.PreKeyRecord; import org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity; import org.whispersystems.textsecure.push.PreKeyList; import org.whispersystems.textsecure.util.Base64; import java.io.File; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.LinkedList; import java.util.List; public class PreKeyUtil { public static final int BATCH_SIZE = 70; public static List generatePreKeys(Context context, MasterSecret masterSecret) { List records = new LinkedList(); long preKeyIdOffset = getNextPreKeyId(context); for (int i=0;i getPreKeys(Context context, MasterSecret masterSecret) { List records = new LinkedList(); File directory = getPreKeysDirectory(context); String[] keyRecordIds = directory.list(); for (String keyRecordId : keyRecordIds) { try { records.add(new PreKeyRecord(context, masterSecret, Long.parseLong(keyRecordId))); } catch (InvalidKeyIdException e) { Log.w("PreKeyUtil", e); new File(getPreKeysDirectory(context), keyRecordId).delete(); } catch (NumberFormatException nfe) { Log.w("PreKeyUtil", nfe); new File(getPreKeysDirectory(context), keyRecordId).delete(); } } return records; } public static void clearPreKeys(Context context) { File directory = getPreKeysDirectory(context); String[] keyRecords = directory.list(); for (String keyRecord : keyRecords) { new File(directory, keyRecord).delete(); } } public static PreKeyList toJson(List records) { List encoded = new LinkedList(); for (PreKeyRecord record : records) { PreKeyEntity entity = PreKeyEntity.newBuilder().setId(record.getId()) .setKey(ByteString.copyFrom(KeyUtil.encodePoint(record.getKeyPair().getPublicKey().getQ()))) .build(); String encodedEntity = Base64.encodeBytesWithoutPadding(entity.toByteArray()); encoded.add(encodedEntity); } return new PreKeyList(encoded); } private static long getNextPreKeyId(Context context) { try { File directory = getPreKeysDirectory(context); String[] keyRecordIds = directory.list(); long nextPreKeyId = 0; for (String keyRecordId : keyRecordIds) { if (Long.parseLong(keyRecordId) > nextPreKeyId) nextPreKeyId = Long.parseLong(keyRecordId); } if (nextPreKeyId == 0) nextPreKeyId = SecureRandom.getInstance("SHA1PRNG").nextInt(Integer.MAX_VALUE/2); return nextPreKeyId; } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } } private static File getPreKeysDirectory(Context context) { File directory = new File(context.getFilesDir(), PreKeyRecord.PREKEY_DIRECTORY); if (!directory.exists()) directory.mkdirs(); return directory; } }