mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 22:59:54 +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;
|
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.AndroidExecutor;
|
||||||
import net.sf.briar.api.android.BundleEncrypter;
|
import net.sf.briar.api.android.BundleEncrypter;
|
||||||
import net.sf.briar.api.android.ReferenceManager;
|
import net.sf.briar.api.android.ReferenceManager;
|
||||||
@@ -16,5 +17,6 @@ public class AndroidModule extends AbstractModule {
|
|||||||
Singleton.class);
|
Singleton.class);
|
||||||
bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in(
|
bind(ReferenceManager.class).to(ReferenceManagerImpl.class).in(
|
||||||
Singleton.class);
|
Singleton.class);
|
||||||
|
requestStaticInjection(AddContactActivity.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package net.sf.briar.android;
|
package net.sf.briar.android;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static javax.crypto.Cipher.DECRYPT_MODE;
|
import static javax.crypto.Cipher.DECRYPT_MODE;
|
||||||
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sf.briar.api.android.BundleEncrypter;
|
import net.sf.briar.api.android.BundleEncrypter;
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
@@ -19,6 +21,9 @@ import com.google.inject.Inject;
|
|||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
class BundleEncrypterImpl implements BundleEncrypter {
|
class BundleEncrypterImpl implements BundleEncrypter {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(BundleEncrypterImpl.class.getName());
|
||||||
|
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final ErasableKey key;
|
private final ErasableKey key;
|
||||||
@@ -40,7 +45,11 @@ class BundleEncrypterImpl implements BundleEncrypter {
|
|||||||
b.writeToParcel(p, 0);
|
b.writeToParcel(p, 0);
|
||||||
byte[] plaintext = p.marshall();
|
byte[] plaintext = p.marshall();
|
||||||
p.recycle();
|
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];
|
byte[] iv = new byte[blockSize];
|
||||||
random.nextBytes(iv);
|
random.nextBytes(iv);
|
||||||
byte[] ciphertext = new byte[plaintext.length + macLength];
|
byte[] ciphertext = new byte[plaintext.length + macLength];
|
||||||
@@ -66,7 +75,7 @@ class BundleEncrypterImpl implements BundleEncrypter {
|
|||||||
byte[] ciphertext = b.getByteArray("net.sf.briar.CIPHERTEXT");
|
byte[] ciphertext = b.getByteArray("net.sf.briar.CIPHERTEXT");
|
||||||
if(ciphertext == null) throw new IllegalArgumentException();
|
if(ciphertext == null) throw new IllegalArgumentException();
|
||||||
if(ciphertext.length < macLength) 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];
|
byte[] plaintext = new byte[ciphertext.length - macLength];
|
||||||
try {
|
try {
|
||||||
cipher.init(DECRYPT_MODE, key, iv, null);
|
cipher.init(DECRYPT_MODE, key, iv, null);
|
||||||
@@ -78,12 +87,14 @@ class BundleEncrypterImpl implements BundleEncrypter {
|
|||||||
Parcel p = Parcel.obtain();
|
Parcel p = Parcel.obtain();
|
||||||
p.unmarshall(plaintext, 0, plaintext.length);
|
p.unmarshall(plaintext, 0, plaintext.length);
|
||||||
ByteUtils.erase(plaintext);
|
ByteUtils.erase(plaintext);
|
||||||
// Replace the IV and the ciphertext with the plaintext contents
|
// Restore the plaintext contents
|
||||||
b.remove("net.sf.briar.IV");
|
|
||||||
b.remove("net.sf.briar.CIPHERTEXT");
|
|
||||||
p.setDataPosition(0);
|
p.setDataPosition(0);
|
||||||
b.readFromParcel(p);
|
b.readFromParcel(p);
|
||||||
p.recycle();
|
p.recycle();
|
||||||
|
if(LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Unmarshalled " + (b.size() - 2) + " mappings, "
|
||||||
|
+ plaintext.length + " plaintext bytes");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import roboguice.activity.RoboActivity;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
public class AddContactActivity extends RoboActivity
|
public class AddContactActivity extends RoboActivity
|
||||||
implements InvitationListener {
|
implements InvitationListener {
|
||||||
@@ -26,12 +27,17 @@ implements InvitationListener {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AddContactActivity.class.getName());
|
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 CryptoComponent crypto;
|
||||||
@Inject private DatabaseComponent db;
|
@Inject private DatabaseComponent db;
|
||||||
@Inject @DatabaseExecutor private Executor dbExecutor;
|
@Inject @DatabaseExecutor private Executor dbExecutor;
|
||||||
@Inject private InvitationTaskFactory invitationTaskFactory;
|
@Inject private InvitationTaskFactory invitationTaskFactory;
|
||||||
@Inject private ReferenceManager referenceManager;
|
@Inject private ReferenceManager referenceManager;
|
||||||
@Inject private BundleEncrypter bundleEncrypter;
|
|
||||||
|
|
||||||
// All of the following must be accessed on the UI thread
|
// All of the following must be accessed on the UI thread
|
||||||
private AddContactView view = null;
|
private AddContactView view = null;
|
||||||
@@ -47,13 +53,13 @@ implements InvitationListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
if(state == null || !bundleEncrypter.decrypt(state)) {
|
||||||
if(state != null && !bundleEncrypter.decrypt(state)) state = null;
|
// This is a new activity or the process has restarted
|
||||||
if(state == null) {
|
super.onCreate(null);
|
||||||
// This is a new activity
|
|
||||||
setView(new NetworkSetupView(this));
|
setView(new NetworkSetupView(this));
|
||||||
} else {
|
} else {
|
||||||
// Restore the activity's state
|
// Restore the activity's state
|
||||||
|
super.onCreate(state);
|
||||||
networkName = state.getString("net.sf.briar.NETWORK_NAME");
|
networkName = state.getString("net.sf.briar.NETWORK_NAME");
|
||||||
useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
|
useBluetooth = state.getBoolean("net.sf.briar.USE_BLUETOOTH");
|
||||||
taskHandle = state.getLong("net.sf.briar.TASK_HANDLE", -1);
|
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
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
@@ -123,16 +135,14 @@ implements InvitationListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle state) {
|
public void onSaveInstanceState(Bundle state) {
|
||||||
super.onSaveInstanceState(state);
|
super.onSaveInstanceState(state);
|
||||||
Bundle b = new Bundle();
|
state.putString("net.sf.briar.NETWORK_NAME", networkName);
|
||||||
b.putString("net.sf.briar.NETWORK_NAME", networkName);
|
state.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
|
||||||
b.putBoolean("net.sf.briar.USE_BLUETOOTH", useBluetooth);
|
state.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
|
||||||
b.putInt("net.sf.briar.LOCAL_CODE", localInvitationCode);
|
state.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
|
||||||
b.putInt("net.sf.briar.REMOTE_CODE", remoteInvitationCode);
|
state.putBoolean("net.sf.briar.FAILED", connectionFailed);
|
||||||
b.putBoolean("net.sf.briar.FAILED", connectionFailed);
|
state.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
|
||||||
b.putBoolean("net.sf.briar.MATCHED", localMatched && remoteMatched);
|
if(task != null) state.putLong("net.sf.briar.TASK_HANDLE", taskHandle);
|
||||||
if(task != null) b.putLong("net.sf.briar.TASK_HANDLE", taskHandle);
|
bundleEncrypter.encrypt(state);
|
||||||
bundleEncrypter.encrypt(b);
|
|
||||||
state.putAll(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user