Move encrypted key, account deletion into AccountManager.

This commit is contained in:
akwizgran
2018-07-23 10:18:38 +01:00
parent cb29c9bf32
commit f9495b49d6
34 changed files with 418 additions and 462 deletions

View File

@@ -1,14 +1,11 @@
package org.briarproject.briar.android;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.File;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.INFO;
@NotNullByDefault
@@ -19,9 +16,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
private final File dbDir, keyDir;
@Nullable
private volatile SecretKey key = null;
AndroidDatabaseConfig(File dbDir, File keyDir) {
this.dbDir = dbDir;
this.keyDir = keyDir;
@@ -62,21 +56,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
return keyDir;
}
@Override
public void setEncryptionKey(SecretKey key) {
LOG.info("Setting database key");
this.key = key;
}
@Override
@Nullable
public SecretKey getEncryptionKey() {
SecretKey key = this.key;
if (LOG.isLoggable(INFO))
LOG.info("Database key has been set: " + (key != null));
return key;
}
@Override
public long getMaxSize() {
return Long.MAX_VALUE;

View File

@@ -9,20 +9,11 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
public class ConfigControllerImpl implements ConfigController {
@@ -30,12 +21,9 @@ public class ConfigControllerImpl implements ConfigController {
Logger.getLogger(ConfigControllerImpl.class.getName());
private static final String PREF_DB_KEY = "key";
private static final String DB_KEY_FILENAME = "db.key";
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
private final SharedPreferences briarPrefs;
private final File dbKeyFile, dbKeyBackupFile;
private final AccountManager accountManager;
protected final AccountManager accountManager;
protected final DatabaseConfig databaseConfig;
@Inject
@@ -44,16 +32,13 @@ public class ConfigControllerImpl implements ConfigController {
this.briarPrefs = briarPrefs;
this.accountManager = accountManager;
this.databaseConfig = databaseConfig;
File keyDir = databaseConfig.getDatabaseKeyDirectory();
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
}
@Override
@Nullable
public String getEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = getDatabaseKeyFromFile();
if (key == null) key = accountManager.getEncryptedDatabaseKey();
else migrateDatabaseKeyToFile(key);
return key;
}
@@ -66,40 +51,8 @@ public class ConfigControllerImpl implements ConfigController {
return key;
}
@Nullable
private String getDatabaseKeyFromFile() {
String key = readDbKeyFromFile(dbKeyFile);
if (key == null) {
LOG.info("No database key in primary file");
key = readDbKeyFromFile(dbKeyBackupFile);
if (key == null) LOG.info("No database key in backup file");
else LOG.warning("Found database key in backup file");
} else {
LOG.info("Found database key in primary file");
}
return key;
}
@Nullable
private String readDbKeyFromFile(File f) {
if (!f.exists()) {
LOG.info("Key file does not exist");
return null;
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(f), "UTF-8"));
String key = reader.readLine();
reader.close();
return key;
} catch (IOException e) {
logException(LOG, WARNING, e);
return null;
}
}
private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) {
if (accountManager.storeEncryptedDatabaseKey(key)) {
if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
@@ -110,47 +63,7 @@ public class ConfigControllerImpl implements ConfigController {
@Override
public boolean storeEncryptedDatabaseKey(String hex) {
LOG.info("Storing database key in file");
// Create the directory if necessary
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
LOG.info("Created database key directory");
// If only the backup file exists, rename it so we don't overwrite it
if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) {
if (dbKeyBackupFile.renameTo(dbKeyFile))
LOG.info("Renamed old backup");
else LOG.warning("Failed to rename old backup");
}
try {
// Write to the backup file
writeDbKeyToFile(hex, dbKeyBackupFile);
LOG.info("Stored database key in backup file");
// Delete the old primary file, if it exists
if (dbKeyFile.exists()) {
if (dbKeyFile.delete()) LOG.info("Deleted primary file");
else LOG.warning("Failed to delete primary file");
}
// The backup file becomes the new primary
if (dbKeyBackupFile.renameTo(dbKeyFile)) {
LOG.info("Renamed backup file to primary");
} else {
LOG.warning("Failed to rename backup file to primary");
return false; // Don't overwrite our only copy
}
// Write a second copy to the backup file
writeDbKeyToFile(hex, dbKeyBackupFile);
LOG.info("Stored second copy of database key in backup file");
return true;
} catch (IOException e) {
logException(LOG, WARNING, e);
return false;
}
}
private void writeDbKeyToFile(String key, File f) throws IOException {
FileOutputStream out = new FileOutputStream(f);
out.write(key.getBytes("UTF-8"));
out.flush();
out.close();
return accountManager.storeEncryptedDatabaseKey(hex);
}
@Override

View File

@@ -57,7 +57,7 @@ public class PasswordControllerImpl extends ConfigControllerImpl
if (key == null) {
resultHandler.onResult(false);
} else {
databaseConfig.setEncryptionKey(new SecretKey(key));
accountManager.setDatabaseKey(new SecretKey(key));
resultHandler.onResult(true);
}
});

View File

@@ -115,7 +115,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
SecretKey key = crypto.generateSecretKey();
String hex = encryptDatabaseKey(key, password);
storeEncryptedDatabaseKey(hex);
databaseConfig.setEncryptionKey(key);
accountManager.setDatabaseKey(key);
resultHandler.onResult(null);
});
}

View File

@@ -1,35 +0,0 @@
package org.briarproject.briar.android;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.annotation.Nullable;
import static junit.framework.Assert.assertTrue;
@NotNullByDefault
public class TestDatabaseKeyUtils {
public static void storeDatabaseKey(File f, String hex) throws IOException {
f.getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(f);
out.write(hex.getBytes("UTF-8"));
out.flush();
out.close();
}
@Nullable
public static String loadDatabaseKey(File f) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(f), "UTF-8"));
String hex = reader.readLine();
reader.close();
return hex;
}
}

View File

@@ -7,21 +7,11 @@ import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.junit.After;
import org.junit.Test;
import java.io.File;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey;
public class ConfigControllerImplTest extends BrambleMockTestCase {
@@ -33,21 +23,15 @@ public class ConfigControllerImplTest extends BrambleMockTestCase {
context.mock(DatabaseConfig.class);
private final Editor editor = context.mock(Editor.class);
private final byte[] encryptedKey = getRandomBytes(123);
private final String encryptedKeyHex = toHexString(encryptedKey);
private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123));
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
@Test
public void testDbKeyIsMigratedFromPreferencesToFile() throws Exception {
public void testDbKeyIsMigratedFromPreferencesToFile() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(encryptedKeyHex));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex);
will(returnValue(true));
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).remove("key");
@@ -56,153 +40,10 @@ public class ConfigControllerImplTest extends BrambleMockTestCase {
will(returnValue(true));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(null));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyFile, encryptedKeyHex);
assertTrue(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
assertTrue(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
}
@Test
public void testDbKeyIsLoadedFromBackupFile() throws Exception {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(null));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertFalse(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
assertFalse(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testDbKeyIsNullIfNotFound() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(null));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertNull(c.getEncryptedDatabaseKey());
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
}
@Test
public void testStoringDbKeyOverwritesPrimary() throws Exception {
context.checking(new Expectations() {{
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyFile, oldEncryptedKeyHex);
assertTrue(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile));
ConfigController c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex));
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test
public void testStoringDbKeyOverwritesBackup() throws Exception {
context.checking(new Expectations() {{
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex);
assertFalse(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
ConfigController c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex));
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}

View File

@@ -9,23 +9,16 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.junit.After;
import org.junit.Test;
import java.io.File;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey;
public class PasswordControllerImplTest extends BrambleMockTestCase {
@@ -46,32 +39,27 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
private final byte[] oldEncryptedKey = getRandomBytes(123);
private final byte[] newEncryptedKey = getRandomBytes(123);
private final byte[] key = getSecretKey().getBytes();
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
private final String oldEncryptedKeyHex = toHexString(oldEncryptedKey);
private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
@Test
public void testChangePasswordReturnsTrue() throws Exception {
public void testChangePasswordReturnsTrue() {
context.checking(new Expectations() {{
// Look up the encrypted DB key
oneOf(briarPrefs).getString("key", null);
will(returnValue(null));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
oneOf(accountManager).getEncryptedDatabaseKey();
will(returnValue(oldEncryptedKeyHex));
// Decrypt and re-encrypt the key
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
will(returnValue(key));
oneOf(crypto).encryptWithPassword(key, newPassword);
will(returnValue(newEncryptedKey));
// Store the new key
oneOf(accountManager).storeEncryptedDatabaseKey(newEncryptedKeyHex);
will(returnValue(true));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator);
@@ -79,34 +67,21 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
AtomicBoolean capturedResult = new AtomicBoolean(false);
p.changePassword(oldPassword, newPassword, capturedResult::set);
assertTrue(capturedResult.get());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(toHexString(newEncryptedKey), loadDatabaseKey(keyFile));
assertEquals(toHexString(newEncryptedKey),
loadDatabaseKey(keyBackupFile));
}
@Test
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong()
throws Exception {
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() {
context.checking(new Expectations() {{
// Look up the encrypted DB key
oneOf(briarPrefs).getString("key", null);
will(returnValue(null));
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
oneOf(accountManager).getEncryptedDatabaseKey();
will(returnValue(oldEncryptedKeyHex));
// Try to decrypt the key - the password is wrong
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
will(returnValue(null));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator);
@@ -114,16 +89,5 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
AtomicBoolean capturedResult = new AtomicBoolean(true);
p.changePassword(oldPassword, newPassword, capturedResult::set);
assertFalse(capturedResult.get());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(toHexString(oldEncryptedKey), loadDatabaseKey(keyFile));
assertEquals(toHexString(oldEncryptedKey),
loadDatabaseKey(keyBackupFile));
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
@@ -14,25 +13,18 @@ import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Test;
import java.io.File;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
public class SetupControllerImplTest extends BrambleMockTestCase {
@@ -55,11 +47,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
private final String password = "some.strong.pass";
private final LocalAuthor localAuthor = getLocalAuthor();
private final byte[] encryptedKey = getRandomBytes(123);
private final String encryptedKeyHex = toHexString(encryptedKey);
private final SecretKey key = getSecretKey();
private final File testDir = getTestDirectory();
private final File keyDir = new File(testDir, "key");
private final File keyFile = new File(keyDir, "db.key");
private final File keyBackupFile = new File(keyDir, "db.key.bak");
public SetupControllerImplTest() {
context.setImposteriser(ClassImposteriser.INSTANCE);
@@ -68,13 +57,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
@Test
@SuppressWarnings("ResultOfMethodCallIgnored")
public void testCreateAccount() throws Exception {
public void testCreateAccount() {
context.checking(new Expectations() {{
// Allow the contents of the data directory to be logged
allowing(setupActivity).getApplicationInfo();
will(returnValue(new ApplicationInfo() {{
dataDir = testDir.getAbsolutePath();
}}));
// Set the author name and password
oneOf(setupActivity).setAuthorName(authorName);
oneOf(setupActivity).setPassword(password);
@@ -94,15 +78,12 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
oneOf(crypto).encryptWithPassword(key.getBytes(), password);
will(returnValue(encryptedKey));
// Store the encrypted key
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
// Attach the database key to the database config
oneOf(databaseConfig).setEncryptionKey(key);
oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex);
will(returnValue(true));
// Pass the database key to the account manager
oneOf(accountManager).setDatabaseKey(key);
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator, identityManager);
@@ -113,17 +94,5 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
s.setPassword(password);
s.createAccount(result -> called.set(true));
assertTrue(called.get());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
assertEquals(toHexString(encryptedKey),
loadDatabaseKey(keyFile));
assertEquals(toHexString(encryptedKey),
loadDatabaseKey(keyBackupFile));
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}