Better FS Locking.

This commit is contained in:
Moxie Marlinspike 2014-05-01 15:02:46 -07:00
parent c8757c2134
commit 79020cd33c
4 changed files with 58 additions and 40 deletions

View File

@ -1,3 +1,13 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
}
apply plugin: 'android-library'
repositories {

View File

@ -25,16 +25,17 @@ public class PreKeyEntity implements PreKey {
@Expose(serialize = false)
private int deviceId;
@Expose(serialize = false)
private int registrationId;
private int keyId;
private ECPublicKey publicKey;
private IdentityKey identityKey;
private int registrationId;
public PreKeyEntity(int keyId, ECPublicKey publicKey, IdentityKey identityKey) {
this.keyId = keyId;
this.publicKey = publicKey;
this.identityKey = identityKey;
this.registrationId = registrationId;
this.keyId = keyId;
this.publicKey = publicKey;
this.identityKey = identityKey;
}
public int getDeviceId() {

View File

@ -22,6 +22,7 @@ public class TextSecurePreKeyStore implements PreKeyStore {
public static final String PREKEY_DIRECTORY = "prekeys";
private static final int CURRENT_VERSION_MARKER = 1;
private static final Object FILE_LOCK = new Object();
private static final String TAG = TextSecurePreKeyStore.class.getSimpleName();
private final Context context;
@ -34,39 +35,43 @@ public class TextSecurePreKeyStore implements PreKeyStore {
@Override
public PreKeyRecord load(int preKeyId) throws InvalidKeyIdException {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
FileInputStream fin = new FileInputStream(getPreKeyFile(preKeyId));
int recordVersion = readInteger(fin);
synchronized (FILE_LOCK) {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
FileInputStream fin = new FileInputStream(getPreKeyFile(preKeyId));
int recordVersion = readInteger(fin);
if (recordVersion != CURRENT_VERSION_MARKER) {
throw new AssertionError("Invalid version: " + recordVersion);
if (recordVersion != CURRENT_VERSION_MARKER) {
throw new AssertionError("Invalid version: " + recordVersion);
}
byte[] serializedRecord = masterCipher.decryptBytes(readBlob(fin));
return new PreKeyRecord(serializedRecord);
} catch (IOException | InvalidMessageException e) {
Log.w(TAG, e);
throw new InvalidKeyIdException(e);
}
byte[] serializedRecord = masterCipher.decryptBytes(readBlob(fin));
return new PreKeyRecord(serializedRecord);
} catch (IOException | InvalidMessageException e) {
Log.w(TAG, e);
throw new InvalidKeyIdException(e);
}
}
@Override
public void store(int preKeyId, PreKeyRecord record) {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
RandomAccessFile recordFile = new RandomAccessFile(getPreKeyFile(preKeyId), "rw");
FileChannel out = recordFile.getChannel();
synchronized (FILE_LOCK) {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
RandomAccessFile recordFile = new RandomAccessFile(getPreKeyFile(preKeyId), "rw");
FileChannel out = recordFile.getChannel();
out.position(0);
writeInteger(CURRENT_VERSION_MARKER, out);
writeBlob(masterCipher.encryptBytes(record.serialize()), out);
out.truncate(out.position());
out.position(0);
writeInteger(CURRENT_VERSION_MARKER, out);
writeBlob(masterCipher.encryptBytes(record.serialize()), out);
out.truncate(out.position());
recordFile.close();
} catch (IOException e) {
throw new AssertionError(e);
recordFile.close();
} catch (IOException e) {
throw new AssertionError(e);
}
}
}

View File

@ -74,19 +74,21 @@ public class TextSecureSessionStore implements SessionStore {
@Override
public void store(long recipientId, int deviceId, SessionRecord record) {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
RandomAccessFile sessionFile = new RandomAccessFile(getSessionFile(recipientId, deviceId), "rw");
FileChannel out = sessionFile.getChannel();
synchronized (FILE_LOCK) {
try {
MasterCipher masterCipher = new MasterCipher(masterSecret);
RandomAccessFile sessionFile = new RandomAccessFile(getSessionFile(recipientId, deviceId), "rw");
FileChannel out = sessionFile.getChannel();
out.position(0);
writeInteger(CURRENT_VERSION, out);
writeBlob(masterCipher.encryptBytes(record.serialize()), out);
out.truncate(out.position());
out.position(0);
writeInteger(CURRENT_VERSION, out);
writeBlob(masterCipher.encryptBytes(record.serialize()), out);
out.truncate(out.position());
sessionFile.close();
} catch (IOException e) {
throw new AssertionError(e);
sessionFile.close();
} catch (IOException e) {
throw new AssertionError(e);
}
}
}