2013-08-18 01:37:18 +00:00
|
|
|
package org.whispersystems.textsecure.crypto;
|
2013-08-15 15:25:30 +00:00
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import com.google.protobuf.ByteString;
|
2013-08-18 01:37:18 +00:00
|
|
|
import org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity;
|
2013-08-15 15:25:30 +00:00
|
|
|
import org.whispersystems.textsecure.push.PreKeyList;
|
2013-08-18 01:37:18 +00:00
|
|
|
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
|
|
|
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
2013-08-15 15:25:30 +00:00
|
|
|
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<PreKeyRecord> generatePreKeys(Context context, MasterSecret masterSecret) {
|
|
|
|
List<PreKeyRecord> records = new LinkedList<PreKeyRecord>();
|
|
|
|
long preKeyIdOffset = getNextPreKeyId(context);
|
|
|
|
|
|
|
|
for (int i=0;i<BATCH_SIZE;i++) {
|
|
|
|
Log.w("PreKeyUtil", "Generating PreKey: " + (preKeyIdOffset + i));
|
2013-08-18 01:37:18 +00:00
|
|
|
PreKeyPair keyPair = new PreKeyPair(masterSecret, KeyUtil.generateKeyPair());
|
2013-08-15 15:25:30 +00:00
|
|
|
PreKeyRecord record = new PreKeyRecord(context, masterSecret, preKeyIdOffset + i, keyPair);
|
|
|
|
|
|
|
|
record.save();
|
|
|
|
records.add(record);
|
|
|
|
}
|
|
|
|
|
|
|
|
return records;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static List<PreKeyRecord> getPreKeys(Context context, MasterSecret masterSecret) {
|
|
|
|
List<PreKeyRecord> records = new LinkedList<PreKeyRecord>();
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|