mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-26 09:59:28 +00:00
Generate "prekeys" at push registration time.
This generates a large number of key exchange messages and registers them with the server during signup.
This commit is contained in:
@@ -19,22 +19,18 @@ package org.thoughtcrime.securesms.database.keys;
|
||||
public class InvalidKeyIdException extends Exception {
|
||||
|
||||
public InvalidKeyIdException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidKeyIdException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidKeyIdException(Throwable throwable) {
|
||||
super(throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InvalidKeyIdException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ import org.thoughtcrime.securesms.crypto.KeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
||||
import org.thoughtcrime.securesms.database.keys.InvalidKeyIdException;
|
||||
import org.thoughtcrime.securesms.database.keys.Record;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
@@ -46,7 +44,7 @@ public class LocalKeyRecord extends Record {
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
public LocalKeyRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||
super(context, getFileNameForRecipient(context, recipient));
|
||||
super(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
loadData();
|
||||
@@ -54,11 +52,11 @@ public class LocalKeyRecord extends Record {
|
||||
|
||||
public static boolean hasRecord(Context context, Recipient recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
Record.delete(context, getFileNameForRecipient(context, recipient));
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||
@@ -121,12 +119,11 @@ public class LocalKeyRecord extends Record {
|
||||
synchronized (FILE_LOCK) {
|
||||
try {
|
||||
FileInputStream in = this.openInputStream();
|
||||
localCurrentKeyPair = readKeyPair(in);
|
||||
localNextKeyPair = readKeyPair(in);
|
||||
localCurrentKeyPair = readKeyPair(in, masterCipher);
|
||||
localNextKeyPair = readKeyPair(in, masterCipher);
|
||||
in.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w("LocalKeyRecord", "No local keypair set found.");
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
Log.w("keyrecord", ioe);
|
||||
// XXX
|
||||
@@ -141,8 +138,11 @@ public class LocalKeyRecord extends Record {
|
||||
writeBlob(keyPairBytes, out);
|
||||
}
|
||||
|
||||
private KeyPair readKeyPair(FileInputStream in) throws IOException, InvalidKeyException {
|
||||
private KeyPair readKeyPair(FileInputStream in, MasterCipher masterCipher)
|
||||
throws IOException, InvalidKeyException
|
||||
{
|
||||
byte[] keyPairBytes = readBlob(in);
|
||||
return new KeyPair(keyPairBytes, masterCipher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
125
src/org/thoughtcrime/securesms/database/keys/PreKeyRecord.java
Normal file
125
src/org/thoughtcrime/securesms/database/keys/PreKeyRecord.java
Normal file
@@ -0,0 +1,125 @@
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.PreKeyPair;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public class PreKeyRecord extends Record {
|
||||
|
||||
private static final Object FILE_LOCK = new Object();
|
||||
private static final int CURRENT_VERSION_MARKER = 1;
|
||||
|
||||
private final MasterCipher masterCipher;
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
private PreKeyPair keyPair;
|
||||
private long id;
|
||||
|
||||
public PreKeyRecord(Context context, MasterSecret masterSecret, long id)
|
||||
throws InvalidKeyIdException
|
||||
{
|
||||
super(context, PREKEY_DIRECTORY, id+"");
|
||||
|
||||
this.id = id;
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
public PreKeyRecord(Context context, MasterSecret masterSecret,
|
||||
long id, PreKeyPair keyPair)
|
||||
{
|
||||
super(context, PREKEY_DIRECTORY, id+"");
|
||||
this.id = id;
|
||||
this.keyPair = keyPair;
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public PreKeyPair getKeyPair() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
public static boolean hasRecord(Context context, long id) {
|
||||
Log.w("PreKeyRecord", "Checking: " + id);
|
||||
return Record.hasRecord(context, PREKEY_DIRECTORY, id+"");
|
||||
}
|
||||
|
||||
public static void delete(Context context, long id) {
|
||||
Record.delete(context, PREKEY_DIRECTORY, id+"");
|
||||
}
|
||||
|
||||
public void save() {
|
||||
synchronized (FILE_LOCK) {
|
||||
try {
|
||||
RandomAccessFile file = openRandomAccessFile();
|
||||
FileChannel out = file.getChannel();
|
||||
out.position(0);
|
||||
|
||||
writeInteger(CURRENT_VERSION_MARKER, out);
|
||||
writeKeyPair(keyPair, out);
|
||||
|
||||
out.force(true);
|
||||
out.truncate(out.position());
|
||||
out.close();
|
||||
file.close();
|
||||
} catch (IOException ioe) {
|
||||
Log.w("PreKeyRecord", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadData() throws InvalidKeyIdException {
|
||||
synchronized (FILE_LOCK) {
|
||||
try {
|
||||
FileInputStream in = this.openInputStream();
|
||||
int recordVersion = readInteger(in);
|
||||
|
||||
if (recordVersion != CURRENT_VERSION_MARKER) {
|
||||
Log.w("PreKeyRecord", "Invalid version: " + recordVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
keyPair = readKeyPair(in, masterCipher);
|
||||
in.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w("PreKeyRecord", e);
|
||||
throw new InvalidKeyIdException(e);
|
||||
} catch (IOException ioe) {
|
||||
Log.w("PreKeyRecord", ioe);
|
||||
throw new InvalidKeyIdException(ioe);
|
||||
} catch (InvalidKeyException ike) {
|
||||
Log.w("LocalKeyRecord", ike);
|
||||
throw new InvalidKeyIdException(ike);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeKeyPair(PreKeyPair keyPair, FileChannel out) throws IOException {
|
||||
byte[] serialized = keyPair.serialize();
|
||||
writeBlob(serialized, out);
|
||||
}
|
||||
|
||||
private PreKeyPair readKeyPair(FileInputStream in, MasterCipher masterCipher)
|
||||
throws IOException, InvalidKeyException
|
||||
{
|
||||
byte[] keyPairBytes = readBlob(in);
|
||||
return new PreKeyPair(masterSecret, keyPairBytes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,9 @@ package org.thoughtcrime.securesms.database.keys;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.KeyPair;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import java.io.File;
|
||||
@@ -30,24 +33,29 @@ import java.nio.channels.FileChannel;
|
||||
|
||||
public abstract class Record {
|
||||
|
||||
protected static final String SESSIONS_DIRECTORY = "sessions";
|
||||
public static final String PREKEY_DIRECTORY = "prekeys";
|
||||
|
||||
protected final String address;
|
||||
protected final String directory;
|
||||
protected final Context context;
|
||||
|
||||
public Record(Context context, String address) {
|
||||
this.context = context;
|
||||
this.address = address;
|
||||
public Record(Context context, String directory, String address) {
|
||||
this.context = context;
|
||||
this.directory = directory;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
delete(this.context, this.address);
|
||||
delete(this.context, this.directory, this.address);
|
||||
}
|
||||
|
||||
protected static void delete(Context context, String address) {
|
||||
getAddressFile(context, address).delete();
|
||||
protected static void delete(Context context, String directory, String address) {
|
||||
getAddressFile(context, directory, address).delete();
|
||||
}
|
||||
|
||||
protected static boolean hasRecord(Context context, String address) {
|
||||
return getAddressFile(context, address).exists();
|
||||
protected static boolean hasRecord(Context context, String directory, String address) {
|
||||
return getAddressFile(context, directory, address).exists();
|
||||
}
|
||||
|
||||
protected RandomAccessFile openRandomAccessFile() throws FileNotFoundException {
|
||||
@@ -59,11 +67,11 @@ public abstract class Record {
|
||||
}
|
||||
|
||||
private File getAddressFile() {
|
||||
return getAddressFile(context, address);
|
||||
return getAddressFile(context, directory, address);
|
||||
}
|
||||
|
||||
private static File getAddressFile(Context context, String address) {
|
||||
return new File(context.getFilesDir().getAbsolutePath() + File.separatorChar + "sessions", address);
|
||||
private static File getAddressFile(Context context, String directory, String address) {
|
||||
return new File(context.getFilesDir().getAbsolutePath() + File.separatorChar + directory, address);
|
||||
}
|
||||
|
||||
protected byte[] readBlob(FileInputStream in) throws IOException {
|
||||
|
||||
@@ -47,17 +47,17 @@ public class RemoteKeyRecord extends Record {
|
||||
private PublicKey remoteKeyLast;
|
||||
|
||||
public RemoteKeyRecord(Context context, Recipient recipient) {
|
||||
super(context,getFileNameForRecipient(context, recipient));
|
||||
super(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
loadData();
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
Record.delete(context, getFileNameForRecipient(context, recipient));
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
public static boolean hasRecord(Context context, Recipient recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||
@@ -126,7 +126,6 @@ public class RemoteKeyRecord extends Record {
|
||||
in.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w("RemoteKeyRecord", "No remote keys found.");
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
Log.w("keyrecord", ioe);
|
||||
// XXX
|
||||
|
||||
@@ -58,19 +58,19 @@ public class SessionRecord extends Record {
|
||||
}
|
||||
|
||||
public SessionRecord(Context context, MasterSecret masterSecret, long recipientId) {
|
||||
super(context, recipientId+"");
|
||||
super(context, SESSIONS_DIRECTORY, recipientId+"");
|
||||
this.masterSecret = masterSecret;
|
||||
this.sessionVersion = 31337;
|
||||
loadData();
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
Record.delete(context, getRecipientId(context, recipient)+"");
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
}
|
||||
|
||||
public static boolean hasSession(Context context, Recipient recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getRecipientId(context, recipient));
|
||||
return Record.hasRecord(context, getRecipientId(context, recipient)+"");
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
}
|
||||
|
||||
private static long getRecipientId(Context context, Recipient recipient) {
|
||||
|
||||
Reference in New Issue
Block a user