From 79020cd33cec56820e1e8dba7c8165475196617b Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Thu, 1 May 2014 15:02:46 -0700 Subject: [PATCH] Better FS Locking. --- libaxolotl/build.gradle | 10 ++++ .../textsecure/push/PreKeyEntity.java | 11 ++-- .../storage/TextSecurePreKeyStore.java | 59 ++++++++++--------- .../storage/TextSecureSessionStore.java | 28 +++++---- 4 files changed, 63 insertions(+), 45 deletions(-) diff --git a/libaxolotl/build.gradle b/libaxolotl/build.gradle index 2774bffb1c..3f418839af 100644 --- a/libaxolotl/build.gradle +++ b/libaxolotl/build.gradle @@ -1,3 +1,13 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:0.9.+' + } +} + apply plugin: 'android-library' repositories { diff --git a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java index c6ddf65650..5bde273a8d 100644 --- a/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java +++ b/library/src/org/whispersystems/textsecure/push/PreKeyEntity.java @@ -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() { diff --git a/library/src/org/whispersystems/textsecure/storage/TextSecurePreKeyStore.java b/library/src/org/whispersystems/textsecure/storage/TextSecurePreKeyStore.java index 15662b7d2c..d56882b715 100644 --- a/library/src/org/whispersystems/textsecure/storage/TextSecurePreKeyStore.java +++ b/library/src/org/whispersystems/textsecure/storage/TextSecurePreKeyStore.java @@ -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); - - if (recordVersion != CURRENT_VERSION_MARKER) { - throw new AssertionError("Invalid version: " + recordVersion); + 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); + } + + 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(); - - 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); + 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()); + + recordFile.close(); + } catch (IOException e) { + throw new AssertionError(e); + } } } diff --git a/library/src/org/whispersystems/textsecure/storage/TextSecureSessionStore.java b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionStore.java index ac170312a3..7c70fa71b5 100644 --- a/library/src/org/whispersystems/textsecure/storage/TextSecureSessionStore.java +++ b/library/src/org/whispersystems/textsecure/storage/TextSecureSessionStore.java @@ -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(); - - 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); + 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()); + + sessionFile.close(); + } catch (IOException e) { + throw new AssertionError(e); + } } }