mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Move DB key management into account manager.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.bramble.account;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
@@ -20,6 +21,8 @@ import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -32,14 +35,16 @@ class AccountManagerImpl implements AccountManager {
|
||||
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
||||
|
||||
private final DatabaseConfig databaseConfig;
|
||||
private final CryptoComponent crypto;
|
||||
private final File dbKeyFile, dbKeyBackupFile;
|
||||
|
||||
@Nullable
|
||||
private volatile SecretKey databaseKey = null;
|
||||
|
||||
@Inject
|
||||
AccountManagerImpl(DatabaseConfig databaseConfig) {
|
||||
AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto) {
|
||||
this.databaseConfig = databaseConfig;
|
||||
this.crypto = crypto;
|
||||
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
||||
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
||||
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
||||
@@ -56,14 +61,8 @@ class AccountManagerImpl implements AccountManager {
|
||||
return databaseKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDatabaseKey(SecretKey k) {
|
||||
databaseKey = k;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getEncryptedDatabaseKey() {
|
||||
protected String loadEncryptedDatabaseKey() {
|
||||
String key = readDbKeyFromFile(dbKeyFile);
|
||||
if (key == null) {
|
||||
LOG.info("No database key in primary file");
|
||||
@@ -94,8 +93,7 @@ class AccountManagerImpl implements AccountManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storeEncryptedDatabaseKey(String hex) {
|
||||
protected boolean storeEncryptedDatabaseKey(String hex) {
|
||||
LOG.info("Storing database key in file");
|
||||
// Create the directory if necessary
|
||||
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
||||
@@ -141,14 +139,58 @@ class AccountManagerImpl implements AccountManager {
|
||||
|
||||
@Override
|
||||
public boolean accountExists() {
|
||||
return getEncryptedDatabaseKey() != null
|
||||
return loadEncryptedDatabaseKey() != null
|
||||
&& databaseConfig.getDatabaseDirectory().isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAccount(String password) {
|
||||
SecretKey key = crypto.generateSecretKey();
|
||||
if (!encryptAndStoreDatabaseKey(key, password)) return false;
|
||||
databaseKey = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) {
|
||||
byte[] plaintext = key.getBytes();
|
||||
byte[] ciphertext = crypto.encryptWithPassword(plaintext, password);
|
||||
return storeEncryptedDatabaseKey(toHexString(ciphertext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAccount() {
|
||||
LOG.info("Deleting account");
|
||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean signIn(String password) {
|
||||
SecretKey key = loadAndDecryptDatabaseKey(password);
|
||||
if (key == null) return false;
|
||||
databaseKey = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SecretKey loadAndDecryptDatabaseKey(String password) {
|
||||
String hex = loadEncryptedDatabaseKey();
|
||||
if (hex == null) {
|
||||
LOG.warning("Failed to load encrypted database key");
|
||||
return null;
|
||||
}
|
||||
byte[] ciphertext = fromHexString(hex);
|
||||
byte[] plaintext = crypto.decryptWithPassword(ciphertext, password);
|
||||
if (plaintext == null) {
|
||||
LOG.info("Failed to decrypt database key");
|
||||
return null;
|
||||
}
|
||||
return new SecretKey(plaintext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changePassword(String oldPassword, String newPassword) {
|
||||
SecretKey key = loadAndDecryptDatabaseKey(oldPassword);
|
||||
return key != null && encryptAndStoreDatabaseKey(key, newPassword);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.bramble.account;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.jmock.Expectations;
|
||||
@@ -29,6 +30,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final DatabaseConfig databaseConfig =
|
||||
context.mock(DatabaseConfig.class);
|
||||
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||
|
||||
private final byte[] encryptedKey = getRandomBytes(123);
|
||||
private final String encryptedKeyHex = toHexString(encryptedKey);
|
||||
@@ -46,7 +48,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
||||
will(returnValue(keyDir));
|
||||
}});
|
||||
accountManager = new AccountManagerImpl(databaseConfig);
|
||||
assertTrue(keyDir.mkdirs());
|
||||
accountManager = new AccountManagerImpl(databaseConfig, crypto);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,7 +63,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
assertFalse(keyBackupFile.exists());
|
||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||
|
||||
assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey());
|
||||
assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey());
|
||||
|
||||
assertTrue(keyFile.exists());
|
||||
assertFalse(keyBackupFile.exists());
|
||||
@@ -78,7 +81,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
assertTrue(keyBackupFile.exists());
|
||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||
|
||||
assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey());
|
||||
assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey());
|
||||
|
||||
assertFalse(keyFile.exists());
|
||||
assertTrue(keyBackupFile.exists());
|
||||
@@ -90,7 +93,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
assertFalse(keyFile.exists());
|
||||
assertFalse(keyBackupFile.exists());
|
||||
|
||||
assertNull(accountManager.getEncryptedDatabaseKey());
|
||||
assertNull(accountManager.loadEncryptedDatabaseKey());
|
||||
|
||||
assertFalse(keyFile.exists());
|
||||
assertFalse(keyBackupFile.exists());
|
||||
@@ -134,13 +137,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
deleteTestDirectory(testDir);
|
||||
}
|
||||
|
||||
private void storeDatabaseKey(File f, String hex) throws IOException {
|
||||
f.getParentFile().mkdirs();
|
||||
FileOutputStream out = new FileOutputStream(f);
|
||||
out.write(hex.getBytes("UTF-8"));
|
||||
out.flush();
|
||||
@@ -155,4 +152,9 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||
reader.close();
|
||||
return hex;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
deleteTestDirectory(testDir);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user