diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 6020c390ae7b5cfb696f052f4b240fb24ef1124e..c2bedce0776881464f6b5e45fc3fb0f46683a398 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -30,7 +30,7 @@
 		</activity>
 		<activity
 			android:name=".android.SetupActivity"
-			android:label="@string/app_name" >
+			android:label="@string/setup_title" >
 		</activity>
 		<activity
 			android:name=".android.SplashScreenActivity"
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 3fda7ccda57bf9a2c69ef56971b4f9699595c82e..e76728dc08554dc0268a3744b9807b32567ea046 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -3,6 +3,13 @@
 	<string name="app_name">Briar</string>
 	<string name="notification_title">Briar is running</string>
 	<string name="notification_text">Touch to quit.</string>
+	<string name="setup_title">Briar Setup</string>
+	<string name="choose_nickname">Choose your nickname:</string>
+	<string name="choose_password">Choose your password:</string>
+	<string name="confirm_password">Confirm your password:</string>
+	<string name="format_min_password">Password must be at least %1$d characters long.</string>
+	<string name="enter_password">Enter your password:</string>
+	<string name="try_again">Wrong password, try again</string>
 	<string name="contact_list_button">Contacts</string>
 	<string name="messages_button">Messages</string>
 	<string name="groups_button">Groups</string>
@@ -29,14 +36,14 @@
 	<string name="format_connecting_wifi">Connecting via %1$s\u2026</string>
 	<string name="connecting_bluetooth">Connecting via Bluetooth\u2026</string>
 	<string name="connection_failed">Connection failed</string>
-	<string name="check_same_network">Please check that you are both using the same network.</string>
+	<string name="check_same_network">Please check that you are both using the same network</string>
 	<string name="try_again_button">Try again</string>
 	<string name="connected_to_contact">Connected to contact</string>
 	<string name="your_confirmation_code">Your confirmation code is</string>
 	<string name="enter_confirmation_code">Please enter your contact\'s confirmation code:</string>
 	<string name="waiting_for_contact">Waiting for contact\u2026</string>
 	<string name="codes_do_not_match">Codes do not match</string>
-	<string name="interfering">This could mean that someone is trying to interfere with your connection.</string>
+	<string name="interfering">This could mean that someone is trying to interfere with your connection</string>
 	<string name="contact_added">Contact added</string>
 	<string name="done_button">Done</string>
 	<string name="messages_title">Messages</string>
@@ -67,7 +74,6 @@
 	<string name="new_blog_item">New blog\u2026</string>
 	<string name="create_nickname_item">New nickname\u2026</string>
 	<string name="create_identity_title">Create an Identity</string>
-	<string name="choose_nickname">Choose your nickname:</string>
 	<string name="create_button">Create</string>
 	<string name="no_contacts">You don\'t have any contacts. Add a contact now?</string>
 	<string name="add_button">Add</string>
diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
index 4f13b65fc2a371d2a7e80bc0468deb9dad3be32f..d71d29f33705a63870c8ac346f35ac5b6d5c6ef8 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -1,10 +1,18 @@
 package net.sf.briar.android;
 
+import static android.text.InputType.TYPE_CLASS_TEXT;
+import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
 import static android.view.Gravity.CENTER;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
+import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
+import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
 import static net.sf.briar.api.messaging.Rating.GOOD;
 
 import java.util.ArrayList;
@@ -22,20 +30,31 @@ import net.sf.briar.android.messages.ConversationListActivity;
 import net.sf.briar.api.LocalAuthor;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.android.ReferenceManager;
+import net.sf.briar.api.crypto.CryptoComponent;
+import net.sf.briar.api.crypto.CryptoExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
+import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DbException;
+import net.sf.briar.util.StringUtils;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.text.Editable;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.BaseAdapter;
 import android.widget.Button;
+import android.widget.EditText;
 import android.widget.GridView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
 
 import com.google.inject.Inject;
 
@@ -48,10 +67,17 @@ public class HomeScreenActivity extends BriarActivity {
 			new BriarServiceConnection();
 
 	@Inject private ReferenceManager referenceManager = null;
+	@Inject private DatabaseConfig databaseConfig = null;
 	@Inject @DatabaseUiExecutor private Executor dbUiExecutor = null;
+	@Inject @CryptoExecutor private Executor cryptoExecutor = null;
+	private boolean bound = false;
+	private TextView tryAgain = null;
+	private Button continueButton = null;
+	private ProgressBar progress = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db = null;
+	@Inject private volatile CryptoComponent crypto = null;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -62,20 +88,23 @@ public class HomeScreenActivity extends BriarActivity {
 		if(quit) {
 			// The activity was launched from the notification bar
 			showSpinner();
+			bindService();
 			quit();
 		} else if(handle != -1) {
 			// The activity was launched from the setup wizard
 			showSpinner();
+			startService(new Intent(BriarService.class.getName()));
+			bindService();
 			storeLocalAuthor(referenceManager.removeReference(handle,
 					LocalAuthor.class));
-		} else {
+		} else if(databaseConfig.getEncryptionKey() == null) {
 			// The activity was launched from the splash screen
+			showPasswordPrompt();
+		} else {
+			// The activity has been launched before
 			showButtons();
+			bindService();
 		}
-		// Start the service and bind to it
-		startService(new Intent(BriarService.class.getName()));
-		bindService(new Intent(BriarService.class.getName()),
-				serviceConnection, 0);
 	}
 
 	private void showSpinner() {
@@ -88,6 +117,11 @@ public class HomeScreenActivity extends BriarActivity {
 		setContentView(layout);
 	}
 
+	private void bindService() {
+		bound = bindService(new Intent(BriarService.class.getName()),
+				serviceConnection, 0);
+	}
+
 	private void quit() {
 		new Thread() {
 			@Override
@@ -145,6 +179,110 @@ public class HomeScreenActivity extends BriarActivity {
 		});
 	}
 
+	private void showPasswordPrompt() {
+		SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
+		String hex = prefs.getString("key", null);
+		if(hex == null) throw new IllegalStateException();
+		final byte[] encrypted = StringUtils.fromHexString(hex);
+
+		LinearLayout layout = new LinearLayout(this);
+		layout.setLayoutParams(MATCH_MATCH);
+		layout.setOrientation(VERTICAL);
+		layout.setGravity(CENTER_HORIZONTAL);
+
+		TextView enterPassword = new TextView(this);
+		enterPassword.setGravity(CENTER);
+		enterPassword.setTextSize(18);
+		enterPassword.setPadding(10, 10, 10, 10);
+		enterPassword.setText(R.string.enter_password);
+		layout.addView(enterPassword);
+
+		final EditText passwordEntry = new EditText(this);
+		passwordEntry.setMaxLines(1);
+		passwordEntry.setPadding(10, 0, 10, 10);
+		int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
+		passwordEntry.setInputType(inputType);
+		passwordEntry.setOnEditorActionListener(new OnEditorActionListener() {
+			public boolean onEditorAction(TextView v, int action, KeyEvent e) {
+				validatePassword(encrypted, passwordEntry.getText());
+				return true;
+			}
+		});
+		layout.addView(passwordEntry);
+
+		tryAgain = new TextView(this);
+		tryAgain.setGravity(CENTER);
+		tryAgain.setTextSize(14);
+		tryAgain.setPadding(10, 10, 10, 10);
+		tryAgain.setText(R.string.try_again);
+		tryAgain.setVisibility(GONE);
+		layout.addView(tryAgain);
+
+		continueButton = new Button(this);
+		continueButton.setLayoutParams(WRAP_WRAP);
+		continueButton.setText(R.string.continue_button);
+		continueButton.setOnClickListener(new OnClickListener() {
+			public void onClick(View v) {
+				validatePassword(encrypted, passwordEntry.getText());
+			}
+		});
+		layout.addView(continueButton);
+
+		progress = new ProgressBar(this);
+		progress.setLayoutParams(WRAP_WRAP);
+		progress.setIndeterminate(true);
+		progress.setVisibility(GONE);
+		layout.addView(progress);
+		setContentView(layout);
+	}
+
+	private void validatePassword(final byte[] encrypted, Editable e) {
+		if(tryAgain == null || continueButton == null || progress == null)
+			return;
+		// Hide the soft keyboard
+		Object o = getSystemService(INPUT_METHOD_SERVICE);
+		((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
+		// Replace the button with a progress bar
+		continueButton.setVisibility(GONE);
+		progress.setVisibility(VISIBLE);
+		// Decrypt the database key in a background thread
+		int length = e.length();
+		final char[] password = new char[length];
+		e.getChars(0, length, password, 0);
+		e.delete(0, length);
+		cryptoExecutor.execute(new Runnable() {
+			public void run() {
+				byte[] key = crypto.decryptWithPassword(encrypted, password);
+				if(key == null) {
+					tryAgain();
+				} else {
+					databaseConfig.setEncryptionKey(key);
+					showButtonsAndStartService();
+				}
+			}
+		});
+	}
+
+	private void tryAgain() {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				tryAgain.setVisibility(VISIBLE);
+				continueButton.setVisibility(VISIBLE);
+				progress.setVisibility(GONE);
+			}
+		});
+	}
+
+	private void showButtonsAndStartService() {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				showButtons();
+				startService(new Intent(BriarService.class.getName()));
+				bindService();
+			}
+		});
+	}
+
 	private void showButtons() {
 		ListView.LayoutParams matchMatch =
 				new ListView.LayoutParams(MATCH_PARENT, MATCH_PARENT);
@@ -227,6 +365,7 @@ public class HomeScreenActivity extends BriarActivity {
 		quitButton.setText(R.string.quit_button);
 		quitButton.setOnClickListener(new OnClickListener() {
 			public void onClick(View view) {
+				showSpinner();
 				quit();
 			}
 		});
@@ -264,6 +403,6 @@ public class HomeScreenActivity extends BriarActivity {
 	@Override
 	public void onDestroy() {
 		super.onDestroy();
-		unbindService(serviceConnection);
+		if(bound) unbindService(serviceConnection);
 	}
 }
diff --git a/briar-android/src/net/sf/briar/android/SetupActivity.java b/briar-android/src/net/sf/briar/android/SetupActivity.java
index a612cc7b28818f0a85399a09fcd342a4429fad7c..a761e7b7f595fb4783d2d5b7c7417e3f0fca09b0 100644
--- a/briar-android/src/net/sf/briar/android/SetupActivity.java
+++ b/briar-android/src/net/sf/briar/android/SetupActivity.java
@@ -3,17 +3,18 @@ package net.sf.briar.android;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.text.InputType.TYPE_CLASS_TEXT;
 import static android.text.InputType.TYPE_TEXT_FLAG_CAP_WORDS;
+import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
 import static android.view.Gravity.CENTER;
 import static android.view.Gravity.CENTER_HORIZONTAL;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
-import static android.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
 import static android.widget.LinearLayout.VERTICAL;
 import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
 import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
 
 import java.io.IOException;
 import java.security.KeyPair;
+import java.util.Arrays;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.R;
@@ -22,31 +23,36 @@ import net.sf.briar.api.LocalAuthor;
 import net.sf.briar.api.android.ReferenceManager;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.CryptoExecutor;
+import net.sf.briar.api.db.DatabaseConfig;
+import net.sf.briar.util.StringUtils;
 import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
 import android.os.Bundle;
-import android.view.KeyEvent;
+import android.text.Editable;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
 
 import com.google.inject.Inject;
 
-public class SetupActivity extends BriarActivity
-implements OnEditorActionListener, OnClickListener {
+public class SetupActivity extends BriarActivity implements OnClickListener {
+
+	private static final int MIN_PASSWORD_LENGTH = 8;
 
 	@Inject @CryptoExecutor private Executor cryptoExecutor;
 	private EditText nicknameEntry = null;
-	private Button createButton = null;
+	private EditText passwordEntry = null, passwordConfirmation = null;
+	private Button continueButton = null;
 	private ProgressBar progress = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile CryptoComponent crypto;
+	@Inject private volatile DatabaseConfig databaseConfig;
 	@Inject private volatile AuthorFactory authorFactory;
 	@Inject private volatile ReferenceManager referenceManager;
 
@@ -69,24 +75,66 @@ implements OnEditorActionListener, OnClickListener {
 			@Override
 			protected void onTextChanged(CharSequence text, int start,
 					int lengthBefore, int lengthAfter) {
-				if(createButton != null)
-					createButton.setEnabled(lengthAfter > 0);
+				enableOrDisableContinueButton();
 			}
 		};
-		nicknameEntry.setTextSize(18);
 		nicknameEntry.setMaxLines(1);
-		nicknameEntry.setPadding(10, 10, 10, 10);
 		int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
 		nicknameEntry.setInputType(inputType);
-		nicknameEntry.setOnEditorActionListener(this);
 		layout.addView(nicknameEntry);
 
-		createButton = new Button(this);
-		createButton.setLayoutParams(WRAP_WRAP);
-		createButton.setText(R.string.create_button);
-		createButton.setEnabled(false);
-		createButton.setOnClickListener(this);
-		layout.addView(createButton);
+		TextView choosePassword = new TextView(this);
+		choosePassword.setGravity(CENTER);
+		choosePassword.setTextSize(18);
+		choosePassword.setPadding(10, 10, 10, 10);
+		choosePassword.setText(R.string.choose_password);
+		layout.addView(choosePassword);
+
+		passwordEntry = new EditText(this) {
+			@Override
+			protected void onTextChanged(CharSequence text, int start,
+					int lengthBefore, int lengthAfter) {
+				enableOrDisableContinueButton();
+			}
+		};
+		passwordEntry.setMaxLines(1);
+		inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
+		passwordEntry.setInputType(inputType);
+		layout.addView(passwordEntry);
+
+		TextView confirmPassword = new TextView(this);
+		confirmPassword.setGravity(CENTER);
+		confirmPassword.setTextSize(18);
+		confirmPassword.setPadding(10, 10, 10, 10);
+		confirmPassword.setText(R.string.confirm_password);
+		layout.addView(confirmPassword);
+
+		passwordConfirmation = new EditText(this) {
+			@Override
+			protected void onTextChanged(CharSequence text, int start,
+					int lengthBefore, int lengthAfter) {
+				enableOrDisableContinueButton();
+			}
+		};
+		passwordConfirmation.setMaxLines(1);
+		inputType = TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD;
+		passwordConfirmation.setInputType(inputType);
+		layout.addView(passwordConfirmation);
+
+		TextView minPasswordLength = new TextView(this);
+		minPasswordLength.setGravity(CENTER);
+		minPasswordLength.setTextSize(14);
+		minPasswordLength.setPadding(10, 10, 10, 10);
+		String format = getResources().getString(R.string.format_min_password);
+		minPasswordLength.setText(String.format(format, MIN_PASSWORD_LENGTH));
+		layout.addView(minPasswordLength);
+
+		continueButton = new Button(this);
+		continueButton.setLayoutParams(WRAP_WRAP);
+		continueButton.setText(R.string.continue_button);
+		continueButton.setEnabled(false);
+		continueButton.setOnClickListener(this);
+		layout.addView(continueButton);
 
 		progress = new ProgressBar(this);
 		progress.setLayoutParams(WRAP_WRAP);
@@ -97,20 +145,42 @@ implements OnEditorActionListener, OnClickListener {
 		setContentView(layout);
 	}
 
-	public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
-		validateNickname();
-		return true;
+	private void enableOrDisableContinueButton() {
+		if(nicknameEntry == null || passwordEntry == null ||
+				passwordConfirmation == null || continueButton == null) return;
+		boolean nicknameNotEmpty = nicknameEntry.getText().length() > 0;
+		char[] firstPassword = getChars(passwordEntry.getText());
+		char[] secondPassword = getChars(passwordConfirmation.getText());
+		boolean passwordLength = firstPassword.length >= MIN_PASSWORD_LENGTH;
+		boolean passwordsMatch = Arrays.equals(firstPassword, secondPassword);
+		for(int i = 0; i < firstPassword.length; i++) firstPassword[i] = 0;
+		for(int i = 0; i < secondPassword.length; i++) secondPassword[i] = 0;
+		boolean valid = nicknameNotEmpty && passwordLength && passwordsMatch;
+		continueButton.setEnabled(valid);
+	}
+
+	private char[] getChars(Editable e) {
+		int length = e.length();
+		char[] c = new char[length];
+		e.getChars(0, length, c, 0);
+		return c;
 	}
 
 	public void onClick(View view) {
-		if(!validateNickname()) return;
 		final String nickname = nicknameEntry.getText().toString();
+		final char[] password = getChars(passwordEntry.getText());
+		delete(passwordEntry.getText());
+		delete(passwordConfirmation.getText());
 		// Replace the button with a progress bar
-		createButton.setVisibility(GONE);
+		continueButton.setVisibility(GONE);
 		progress.setVisibility(VISIBLE);
-		// Create the identity in a background thread
+		// Store the DB key and create the identity in a background thread
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
+				byte[] key = crypto.generateSecretKey().getEncoded();
+				byte[] encrypted = crypto.encryptWithPassword(key, password);
+				storeEncryptedDatabaseKey(encrypted);
+				databaseConfig.setEncryptionKey(key);
 				KeyPair keyPair = crypto.generateSignatureKeyPair();
 				final byte[] publicKey = keyPair.getPublic().getEncoded();
 				final byte[] privateKey = keyPair.getPrivate().getEncoded();
@@ -127,6 +197,17 @@ implements OnEditorActionListener, OnClickListener {
 		});
 	}
 
+	private void delete(Editable e) {
+		e.delete(0, e.length());
+	}
+
+	private void storeEncryptedDatabaseKey(byte[] encrypted) {
+		SharedPreferences prefs = getSharedPreferences("db", MODE_PRIVATE);
+		Editor editor = prefs.edit();
+		editor.putString("key", StringUtils.toHexString(encrypted));
+		editor.commit();
+	}
+
 	private void showHomeScreen(final long handle) {
 		runOnUiThread(new Runnable() {
 			public void run() {
@@ -139,12 +220,4 @@ implements OnEditorActionListener, OnClickListener {
 			}
 		});
 	}
-
-	private boolean validateNickname() {
-		if(nicknameEntry.getText().toString().equals("")) return false;
-		// Hide the soft keyboard
-		Object o = getSystemService(INPUT_METHOD_SERVICE);
-		((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
-		return true;
-	}
 }
diff --git a/briar-android/src/net/sf/briar/android/SplashScreenActivity.java b/briar-android/src/net/sf/briar/android/SplashScreenActivity.java
index 54d529c8c996cfbd18fd4317575cccbef6fc19f3..2c1e6000566a50e3ae1ab459ffde337530de21ee 100644
--- a/briar-android/src/net/sf/briar/android/SplashScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/SplashScreenActivity.java
@@ -2,7 +2,7 @@ package net.sf.briar.android;
 
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.view.Gravity.CENTER;
-import net.sf.briar.android.widgets.CommonLayoutParams;
+import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_MATCH;
 import net.sf.briar.api.db.DatabaseConfig;
 import roboguice.RoboGuice;
 import roboguice.activity.RoboSplashActivity;
@@ -24,7 +24,7 @@ public class SplashScreenActivity extends RoboSplashActivity {
 	public void onCreate(Bundle state) {
 		super.onCreate(null);
 		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(CommonLayoutParams.MATCH_MATCH);
+		layout.setLayoutParams(MATCH_MATCH);
 		layout.setGravity(CENTER);
 		ProgressBar spinner = new ProgressBar(this);
 		spinner.setIndeterminate(true);
diff --git a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java
index e62dff274a37f50f31a6d4e3d91beb5ec80752aa..c3025a62d42f07fb56217f59bf93df0520d25c2b 100644
--- a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java
+++ b/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java
@@ -99,9 +99,8 @@ SelectContactsDialog.Listener {
 				enableOrDisableCreateButton();
 			}
 		};
-		nameEntry.setTextSize(18);
 		nameEntry.setMaxLines(1);
-		nameEntry.setPadding(10, 10, 10, 10);
+		nameEntry.setPadding(10, 0, 10, 10);
 		nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
 		nameEntry.setOnEditorActionListener(this);
 		layout.addView(nameEntry);
diff --git a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
index 028d0cccd93f5eb95dd134afbe7fbf1a5694d926..e6dab7ed0269620112a49091e63acde229cf8053 100644
--- a/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/CreateGroupActivity.java
@@ -94,9 +94,8 @@ SelectContactsDialog.Listener {
 				enableOrDisableCreateButton();
 			}
 		};
-		nameEntry.setTextSize(18);
 		nameEntry.setMaxLines(1);
-		nameEntry.setPadding(10, 10, 10, 10);
+		nameEntry.setPadding(10, 0, 10, 10);
 		nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
 		nameEntry.setOnEditorActionListener(this);
 		layout.addView(nameEntry);
diff --git a/briar-android/src/net/sf/briar/android/helloworld/HelloWorldModule.java b/briar-android/src/net/sf/briar/android/helloworld/HelloWorldModule.java
index b95de675f116a8269d4b200eeb64b35e774f7ca5..1880ece374d10bfb3eccb3ebbd06ddb01af8476e 100644
--- a/briar-android/src/net/sf/briar/android/helloworld/HelloWorldModule.java
+++ b/briar-android/src/net/sf/briar/android/helloworld/HelloWorldModule.java
@@ -35,6 +35,8 @@ public class HelloWorldModule extends AbstractModule {
 		final File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
 		return new DatabaseConfig() {
 
+			private volatile byte[] key = null;
+
 			public boolean databaseExists() {
 				return dir.isDirectory() && dir.listFiles().length > 0;
 			}
@@ -43,8 +45,12 @@ public class HelloWorldModule extends AbstractModule {
 				return dir;
 			}
 
-			public char[] getPassword() {
-				return "foo bar".toCharArray();
+			public void setEncryptionKey(byte[] key) {
+				this.key = key;
+			}
+
+			public byte[] getEncryptionKey() {
+				return key;
 			}
 
 			public long getMaxSize() {
diff --git a/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java b/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java
index d91a2f95247d34be31d35baa3530498d3e4a128b..e0d9493ece11783b611919b27da536db7bc3b2ff 100644
--- a/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java
+++ b/briar-android/src/net/sf/briar/android/identity/CreateIdentityActivity.java
@@ -85,12 +85,11 @@ implements OnEditorActionListener, OnClickListener {
 			protected void onTextChanged(CharSequence text, int start,
 					int lengthBefore, int lengthAfter) {
 				if(createButton != null)
-					createButton.setEnabled(lengthAfter > 0);
+					createButton.setEnabled(getText().length() > 0);
 			}
 		};
-		nicknameEntry.setTextSize(18);
 		nicknameEntry.setMaxLines(1);
-		nicknameEntry.setPadding(10, 10, 10, 10);
+		nicknameEntry.setPadding(10, 0, 10, 10);
 		int inputType = TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_WORDS;
 		nicknameEntry.setInputType(inputType);
 		nicknameEntry.setOnEditorActionListener(this);
diff --git a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
index 728a28e5f431de89aa11391b5eebb7113f6e49ba..866c4bdaa51fba5e42c4f92f28f7ee1f2d27db74 100644
--- a/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/WritePrivateMessageActivity.java
@@ -96,7 +96,6 @@ implements OnItemSelectedListener, OnClickListener {
 
 		from = new TextView(this);
 		from.setTextSize(18);
-		from.setMaxLines(1);
 		from.setPadding(10, 10, 10, 10);
 		from.setText(R.string.from);
 		header.addView(from);
diff --git a/briar-api/src/net/sf/briar/api/db/DatabaseConfig.java b/briar-api/src/net/sf/briar/api/db/DatabaseConfig.java
index 15f27b645e3afcf7838c99e53e6370dd401655c0..26f42f99d96d2ed8813c58ac94fabf0228fc0162 100644
--- a/briar-api/src/net/sf/briar/api/db/DatabaseConfig.java
+++ b/briar-api/src/net/sf/briar/api/db/DatabaseConfig.java
@@ -8,7 +8,9 @@ public interface DatabaseConfig {
 
 	File getDatabaseDirectory();
 
-	char[] getPassword();
+	void setEncryptionKey(byte[] key);
+
+	byte[] getEncryptionKey();
 
 	long getMaxSize();
 }
diff --git a/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java b/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
index 7526c3708da9fba24eece4402d02f33c9883c330..c846af33a55d6d2c39e4d60ffeb19f005373121e 100644
--- a/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
+++ b/briar-core/src/net/sf/briar/crypto/CryptoComponentImpl.java
@@ -65,7 +65,7 @@ class CryptoComponentImpl implements CryptoComponent {
 	private static final String STORAGE_CIPHER_ALGO = "AES/GCM/NoPadding";
 	private static final int STORAGE_IV_BYTES = 16; // 128 bits
 	private static final int PBKDF_SALT_BYTES = 16; // 128 bits
-	private static final int PBKDF_ITERATIONS = 10 * 1000; // FIXME: How many?
+	private static final int PBKDF_ITERATIONS = 1000;
 	private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
 	private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
 
diff --git a/briar-core/src/net/sf/briar/db/H2Database.java b/briar-core/src/net/sf/briar/db/H2Database.java
index 18fe2bdd7638ce7db6b7d73b59b35d6e74d95030..5203f64830c1c01b05c1fc1b58f7aba9ce011d45 100644
--- a/briar-core/src/net/sf/briar/db/H2Database.java
+++ b/briar-core/src/net/sf/briar/db/H2Database.java
@@ -5,13 +5,13 @@ import java.io.IOException;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
-import java.util.Arrays;
 import java.util.Properties;
 
 import net.sf.briar.api.clock.Clock;
 import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.util.FileUtils;
+import net.sf.briar.util.StringUtils;
 
 import com.google.inject.Inject;
 
@@ -23,23 +23,23 @@ class H2Database extends JdbcDatabase {
 	private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
 	private static final String SECRET_TYPE = "BINARY(32)";
 
-	private final File dir;
+	private final DatabaseConfig config;
 	private final String url;
-	private final char[] password;
-	private final long maxSize;
 
 	@Inject
 	H2Database(DatabaseConfig config, Clock clock) {
-		super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, config, clock);
-		dir = config.getDatabaseDirectory();
-		url = "jdbc:h2:split:" + new File(dir, "db").getPath()
+		super(HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE, clock);
+		this.config = config;
+		String path = new File(config.getDatabaseDirectory(), "db").getPath();
+		url = "jdbc:h2:split:" + path
 				+ ";CIPHER=AES;MULTI_THREADED=1;DB_CLOSE_ON_EXIT=false";
-		password = config.getPassword();
-		maxSize = config.getMaxSize();
 	}
 
 	public boolean open() throws DbException, IOException {
-		return super.open("org.h2.Driver");
+		boolean reopen = config.databaseExists();
+		if(!reopen) config.getDatabaseDirectory().mkdirs();
+		super.open("org.h2.Driver", reopen);
+		return reopen;
 	}
 
 	public void close() throws DbException {
@@ -52,6 +52,8 @@ class H2Database extends JdbcDatabase {
 	}
 
 	public long getFreeSpace() throws DbException {
+		File dir = config.getDatabaseDirectory();
+		long maxSize = config.getMaxSize();
 		try {
 			long free = FileUtils.getFreeSpace(dir);
 			long used = getDiskSpace(dir);
@@ -73,14 +75,28 @@ class H2Database extends JdbcDatabase {
 
 	@Override
 	protected Connection createConnection() throws SQLException {
-		char[] passwordCopy = password.clone();
+		char[] password = encodePassword(config.getEncryptionKey());
 		Properties props = new Properties();
 		props.setProperty("user", "user");
-		props.put("password", passwordCopy);
+		props.put("password", password);
 		try {
 			return DriverManager.getConnection(url, props);
 		} finally {
-			Arrays.fill(passwordCopy, (char) 0);
+			for(int i = 0; i < password.length; i++) password[i] = 0;
 		}
 	}
+
+	private char[] encodePassword(byte[] key) {
+		// The database password is the hex-encoded key
+		char[] hex = StringUtils.toHexChars(key);
+		// Separate the database password from the user password with a space
+		char[] user = "password".toCharArray();
+		char[] combined = new char[hex.length + 1 + user.length];
+		System.arraycopy(hex, 0, combined, 0, hex.length);
+		combined[hex.length] = ' ';
+		System.arraycopy(user, 0, combined, hex.length + 1, user.length);
+		// Erase the hex-encoded key
+		for(int i = 0; i < hex.length; i++) hex[i] = 0;
+		return combined;
+	}
 }
diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
index 742cb6cdb14b89308192421be8543e977e449c51..d33c66950ed114611268b634c25b995e186e26cb 100644
--- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java
+++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java
@@ -34,7 +34,6 @@ import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportId;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.clock.Clock;
-import net.sf.briar.api.db.DatabaseConfig;
 import net.sf.briar.api.db.DbClosedException;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.db.GroupMessageHeader;
@@ -360,7 +359,6 @@ abstract class JdbcDatabase implements Database<Connection> {
 
 	// Different database libraries use different names for certain types
 	private final String hashType, binaryType, counterType, secretType;
-	private final DatabaseConfig config;
 	private final Clock clock;
 
 	private final LinkedList<Connection> connections =
@@ -372,18 +370,16 @@ abstract class JdbcDatabase implements Database<Connection> {
 	protected abstract Connection createConnection() throws SQLException;
 
 	JdbcDatabase(String hashType, String binaryType, String counterType,
-			String secretType, DatabaseConfig config, Clock clock) {
+			String secretType, Clock clock) {
 		this.hashType = hashType;
 		this.binaryType = binaryType;
 		this.counterType = counterType;
 		this.secretType = secretType;
-		this.config = config;
 		this.clock = clock;
 	}
 
-	protected boolean open(String driverClass) throws DbException, IOException {
-		boolean reopen = config.databaseExists();
-		if(!reopen) config.getDatabaseDirectory().mkdirs();
+	protected void open(String driverClass, boolean reopen) throws DbException,
+	IOException {
 		// Load the JDBC driver
 		try {
 			Class.forName(driverClass);
@@ -399,7 +395,6 @@ abstract class JdbcDatabase implements Database<Connection> {
 			abortTransaction(txn);
 			throw e;
 		}
-		return reopen;
 	}
 
 	private void createTables(Connection txn) throws DbException {
diff --git a/briar-core/src/net/sf/briar/util/StringUtils.java b/briar-core/src/net/sf/briar/util/StringUtils.java
index 0b3e674fd86046a29c7b8314c4565098b81077d7..a7d71ea8ac4655c7afa9bf0fa8b4db6fc26bd4f2 100644
--- a/briar-core/src/net/sf/briar/util/StringUtils.java
+++ b/briar-core/src/net/sf/briar/util/StringUtils.java
@@ -29,16 +29,19 @@ public class StringUtils {
 		else return s;
 	}
 
+	/** Converts the given byte array to a hex character array. */
+	public static char[] toHexChars(byte[] bytes) {
+		char[] hex = new char[bytes.length * 2];
+		for(int i = 0, j = 0; i < bytes.length; i++) {
+			hex[j++] = HEX[(bytes[i] >> 4) & 0xF];
+			hex[j++] = HEX[bytes[i] & 0xF];
+		}
+		return hex;
+	}
+
 	/** Converts the given byte array to a hex string. */
 	public static String toHexString(byte[] bytes) {
-		StringBuilder s = new StringBuilder(bytes.length * 2);
-		for(byte b : bytes) {
-			int high = (b >> 4) & 0xF;
-			s.append(HEX[high]);
-			int low = b & 0xF;
-			s.append(HEX[low]);
-		}
-		return s.toString();
+		return new String(toHexChars(bytes));
 	}
 
 	/** Converts the given hex string to a byte array. */
diff --git a/briar-tests/src/net/sf/briar/TestDatabaseConfig.java b/briar-tests/src/net/sf/briar/TestDatabaseConfig.java
index e21336822f4b724f5ff279ecc15de9a97700c614..1d01590cf4cf0b4b0560c99cb7c766a362017541 100644
--- a/briar-tests/src/net/sf/briar/TestDatabaseConfig.java
+++ b/briar-tests/src/net/sf/briar/TestDatabaseConfig.java
@@ -8,6 +8,7 @@ public class TestDatabaseConfig implements DatabaseConfig {
 
 	private final File dir;
 	private final long maxSize;
+	private volatile byte[] key = new byte[] { 'f', 'o', 'o' };
 
 	public TestDatabaseConfig(File dir, long maxSize) {
 		this.dir = dir;
@@ -22,8 +23,12 @@ public class TestDatabaseConfig implements DatabaseConfig {
 		return dir;
 	}
 
-	public char[] getPassword() {
-		return "foo bar".toCharArray();
+	public void setEncryptionKey(byte[] key) {
+		this.key = key;
+	}
+
+	public byte[] getEncryptionKey() {
+		return key;
 	}
 
 	public long getMaxSize() {