From f33348ff98997f560b9cbc24572015254f842b81 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Tue, 19 Feb 2013 00:11:10 +0000 Subject: [PATCH] Use static injection to allow superclass state to be encrypted. Mutable static fields should be avoided, but this is the only way to make the bundle encrypter available before calling RoboActivity.onCreate(), which needs to be passed the decrypted state. --- .../net/sf/briar/android/AndroidModule.java | 2 + .../sf/briar/android/BundleEncrypterImpl.java | 21 +++++++--- .../invitation/AddContactActivity.java | 40 ++++++++++++------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/briar-android/src/net/sf/briar/android/AndroidModule.java b/briar-android/src/net/sf/briar/android/AndroidModule.java index 83ec347370..d379f5086c 100644 --- a/briar-android/src/net/sf/briar/android/AndroidModule.java +++ b/briar-android/src/net/sf/briar/android/AndroidModule.java @@ -1,5 +1,6 @@ package net.sf.briar.android; +import net.sf.briar.android.invitation.AddContactActivity; import net.sf.briar.api.android.AndroidExecutor; import net.sf.briar.api.android.BundleEncrypter; import net.sf.briar.api.android.ReferenceManager; @@ -16,5 +17,6 @@ public class AndroidModule extends AbstractModule { Singleton.class); bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in( Singleton.class); + requestStaticInjection(AddContactActivity.class); } } diff --git a/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java b/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java index ce8f9912d7..68305ffe6c 100644 --- a/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java +++ b/briar-android/src/net/sf/briar/android/BundleEncrypterImpl.java @@ -1,10 +1,12 @@ package net.sf.briar.android; +import static java.util.logging.Level.INFO; import static javax.crypto.Cipher.DECRYPT_MODE; import static javax.crypto.Cipher.ENCRYPT_MODE; import java.security.GeneralSecurityException; import java.security.SecureRandom; +import java.util.logging.Logger; import net.sf.briar.api.android.BundleEncrypter; import net.sf.briar.api.crypto.AuthenticatedCipher; @@ -19,6 +21,9 @@ import com.google.inject.Inject; // This class is not thread-safe class BundleEncrypterImpl implements BundleEncrypter { + private static final Logger LOG = + Logger.getLogger(BundleEncrypterImpl.class.getName()); + private final AuthenticatedCipher cipher; private final SecureRandom random; private final ErasableKey key; @@ -40,7 +45,11 @@ class BundleEncrypterImpl implements BundleEncrypter { b.writeToParcel(p, 0); byte[] plaintext = p.marshall(); p.recycle(); - // Encrypt the byte array using the storage key and a random IV + if(LOG.isLoggable(INFO)) { + LOG.info("Marshalled " + b.size() + " mappings, " + + plaintext.length + " plaintext bytes"); + } + // Encrypt the byte array using a random IV byte[] iv = new byte[blockSize]; random.nextBytes(iv); byte[] ciphertext = new byte[plaintext.length + macLength]; @@ -66,7 +75,7 @@ class BundleEncrypterImpl implements BundleEncrypter { byte[] ciphertext = b.getByteArray("net.sf.briar.CIPHERTEXT"); if(ciphertext == null) throw new IllegalArgumentException(); if(ciphertext.length < macLength) throw new IllegalArgumentException(); - // Decrypt the ciphertext using the storage key and the IV + // Decrypt the ciphertext using the IV byte[] plaintext = new byte[ciphertext.length - macLength]; try { cipher.init(DECRYPT_MODE, key, iv, null); @@ -78,12 +87,14 @@ class BundleEncrypterImpl implements BundleEncrypter { Parcel p = Parcel.obtain(); p.unmarshall(plaintext, 0, plaintext.length); ByteUtils.erase(plaintext); - // Replace the IV and the ciphertext with the plaintext contents - b.remove("net.sf.briar.IV"); - b.remove("net.sf.briar.CIPHERTEXT"); + // Restore the plaintext contents p.setDataPosition(0); b.readFromParcel(p); p.recycle(); + if(LOG.isLoggable(INFO)) { + LOG.info("Unmarshalled " + (b.size() - 2) + " mappings, " + + plaintext.length + " plaintext bytes"); + } return true; } } diff --git a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java index 5de5df339e..4b25d2a894 100644 --- a/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java +++ b/briar-android/src/net/sf/briar/android/invitation/AddContactActivity.java @@ -19,6 +19,7 @@ import roboguice.activity.RoboActivity; import android.os.Bundle; import com.google.inject.Inject; +import com.google.inject.Provider; public class AddContactActivity extends RoboActivity implements InvitationListener { @@ -26,12 +27,17 @@ implements InvitationListener { private static final Logger LOG = Logger.getLogger(AddContactActivity.class.getName()); + // This allows us to access bundleEncrypter before calling super.onCreate() + @Inject private static Provider<BundleEncrypter> bundleEncrypterProvider; + + private final BundleEncrypter bundleEncrypter = + bundleEncrypterProvider.get(); + @Inject private CryptoComponent crypto; @Inject private DatabaseComponent db; @Inject @DatabaseExecutor private Executor dbExecutor; @Inject private InvitationTaskFactory invitationTaskFactory; @Inject private ReferenceManager referenceManager; - @Inject private BundleEncrypter bundleEncrypter; // All of the following must be accessed on the UI thread private AddContactView view = null; @@ -47,13 +53,13 @@ implements InvitationListener { @Override public void onCreate(Bundle state) { - super.onCreate(state); - if(state != null && !bundleEncrypter.decrypt(state)) state = null; - if(state == null) { - // This is a new activity + if(state == null || !bundleEncrypter.decrypt(state)) { + // This is a new activity or the process has restarted + super.onCreate(null); setView(new NetworkSetupView(this)); } else { // Restore the activity's state + super.onCreate(state); networkName = state.getString("net.sf.briar.NETWORK_NAME"); useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH"); taskHandle = state.getLong("net.sf.briar.TASK_HANDLE", -1); @@ -114,6 +120,12 @@ implements InvitationListener { } } + @Override + public void onRestoreInstanceState(Bundle state) { + if(bundleEncrypter.decrypt(state)) + super.onRestoreInstanceState(state); + } + @Override public void onResume() { super.onResume(); @@ -123,16 +135,14 @@ implements InvitationListener { @Override public void onSaveInstanceState(Bundle state) { super.onSaveInstanceState(state); - Bundle b = new Bundle(); - b.putString("net.sf.briar.NETWORK_NAME", networkName); - b.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth); - b.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode); - b.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode); - b.putBoolean("net.sf.briar.FAILED", connectionFailed); - b.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched); - if(task != null) b.putLong("net.sf.briar.TASK_HANDLE", taskHandle); - bundleEncrypter.encrypt(b); - state.putAll(b); + state.putString("net.sf.briar.NETWORK_NAME", networkName); + state.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth); + state.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode); + state.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode); + state.putBoolean("net.sf.briar.FAILED", connectionFailed); + state.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched); + if(task != null) state.putLong("net.sf.briar.TASK_HANDLE", taskHandle); + bundleEncrypter.encrypt(state); } @Override -- GitLab