mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user