Store database key in a file rather than shared prefs.

This commit is contained in:
akwizgran
2018-05-18 14:47:53 +01:00
parent cfdbd29cb4
commit 21dae824a6
10 changed files with 251 additions and 67 deletions

View File

@@ -17,31 +17,32 @@ class AndroidDatabaseConfig implements DatabaseConfig {
private static final Logger LOG =
Logger.getLogger(AndroidDatabaseConfig.class.getName());
private final File dir;
private final File dbDir, keyDir;
@Nullable
private volatile SecretKey key = null;
@Nullable
private volatile String nickname = null;
AndroidDatabaseConfig(File dir) {
this.dir = dir;
AndroidDatabaseConfig(File dbDir, File keyDir) {
this.dbDir = dbDir;
this.keyDir = keyDir;
}
@Override
public boolean databaseExists() {
// FIXME should not run on UiThread #620
if (!dir.isDirectory()) {
if (!dbDir.isDirectory()) {
if (LOG.isLoggable(INFO))
LOG.info(dir.getAbsolutePath() + " is not a directory");
LOG.info(dbDir.getAbsolutePath() + " is not a directory");
return false;
}
File[] files = dir.listFiles();
File[] files = dbDir.listFiles();
if (LOG.isLoggable(INFO)) {
if (files == null) {
LOG.info("Could not list files in " + dir.getAbsolutePath());
LOG.info("Could not list files in " + dbDir.getAbsolutePath());
} else {
LOG.info("Files in " + dir.getAbsolutePath() + ":");
LOG.info("Files in " + dbDir.getAbsolutePath() + ":");
for (File f : files) LOG.info(f.getName());
}
LOG.info("Database exists: " + (files != null && files.length > 0));
@@ -51,10 +52,16 @@ class AndroidDatabaseConfig implements DatabaseConfig {
@Override
public File getDatabaseDirectory() {
File dir = this.dir;
if (LOG.isLoggable(INFO))
LOG.info("Database directory: " + dir.getAbsolutePath());
return dir;
LOG.info("Database directory: " + dbDir.getAbsolutePath());
return dbDir;
}
@Override
public File getDatabaseKeyDirectory() {
if (LOG.isLoggable(INFO))
LOG.info("Database key directory: " + keyDir.getAbsolutePath());
return keyDir;
}
@Override

View File

@@ -87,11 +87,13 @@ public class AppModule {
//FIXME: StrictMode
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskReads();
StrictMode.allowThreadDiskWrites();
File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE);
StrictMode.setThreadPolicy(tp);
@MethodsNotNullByDefault
@ParametersNotNullByDefault
DatabaseConfig databaseConfig = new AndroidDatabaseConfig(dir);
DatabaseConfig databaseConfig =
new AndroidDatabaseConfig(dbDir, keyDir);
return databaseConfig;
}

View File

@@ -12,7 +12,7 @@ public interface ConfigController {
@Nullable
String getEncryptedDatabaseKey();
void storeEncryptedDatabaseKey(String hex);
boolean storeEncryptedDatabaseKey(String hex);
void deleteAccount(Context ctx);

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.android.controller;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.preference.PreferenceManager;
@@ -9,12 +8,19 @@ 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.INFO;
import static java.util.logging.Level.WARNING;
@NotNullByDefault
public class ConfigControllerImpl implements ConfigController {
@@ -23,6 +29,8 @@ 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;
protected final DatabaseConfig databaseConfig;
@@ -37,17 +45,101 @@ public class ConfigControllerImpl implements ConfigController {
@Override
@Nullable
public String getEncryptedDatabaseKey() {
String key = briarPrefs.getString(PREF_DB_KEY, null);
if (LOG.isLoggable(INFO))
LOG.info("Got database key from preferences: " + (key != null));
String key = getDatabaseKeyFromPreferences();
if (key == null) key = getDatabaseKeyFromFile();
else migrateDatabaseKeyToFile(key);
return key;
}
@Nullable
private String getDatabaseKeyFromPreferences() {
String key = briarPrefs.getString(PREF_DB_KEY, null);
if (key == null) LOG.info("No database key in preferences");
else LOG.info("Found database key in preferences");
return key;
}
@Nullable
private String getDatabaseKeyFromFile() {
String key = readDbKeyFromFile(getDbKeyFile());
if (key == null) {
LOG.info("No database key in primary file");
key = readDbKeyFromFile(getDbKeyBackupFile());
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) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
}
private File getDbKeyFile() {
return new File(databaseConfig.getDatabaseKeyDirectory(),
DB_KEY_FILENAME);
}
private File getDbKeyBackupFile() {
return new File(databaseConfig.getDatabaseKeyDirectory(),
DB_KEY_BACKUP_FILENAME);
}
private void migrateDatabaseKeyToFile(String key) {
if (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");
} else {
LOG.warning("Database key not migrated to file");
}
}
@Override
@SuppressLint("ApplySharedPref")
public void storeEncryptedDatabaseKey(String hex) {
LOG.info("Storing database key in preferences");
briarPrefs.edit().putString(PREF_DB_KEY, hex).commit();
public boolean storeEncryptedDatabaseKey(String hex) {
LOG.info("Storing database key in file");
File dbKey = getDbKeyFile();
File dbKeyBackup = getDbKeyBackupFile();
try {
// Create the directory if necessary
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
LOG.info("Created database key directory");
// Write to the backup file
FileOutputStream out = new FileOutputStream(dbKeyBackup);
out.write(hex.getBytes("UTF-8"));
out.flush();
out.close();
LOG.info("Stored database key in backup file");
// Delete the old key file, if it exists
if (dbKey.exists()) {
if (dbKey.delete()) LOG.info("Deleted primary file");
else LOG.warning("Failed to delete primary file");
}
// The backup file becomes the new key file
boolean renamed = dbKeyBackup.renameTo(dbKey);
if (renamed) LOG.info("Renamed backup file to primary");
else LOG.warning("Failed to rename backup file to primary");
return renamed;
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return false;
}
}
@Override
@@ -73,5 +165,4 @@ public class ConfigControllerImpl implements ConfigController {
if (LOG.isLoggable(INFO)) LOG.info("Signed in: " + signedIn);
return signedIn;
}
}

View File

@@ -72,8 +72,8 @@ public class PasswordControllerImpl extends ConfigControllerImpl
} else {
String hex =
encryptDatabaseKey(new SecretKey(key), newPassword);
storeEncryptedDatabaseKey(hex);
resultHandler.onResult(true);
boolean stored = storeEncryptedDatabaseKey(hex);
resultHandler.onResult(stored);
}
});
}