Re-encrypt the DB key with the stored key.

This commit is contained in:
akwizgran
2020-01-09 14:32:11 +00:00
parent d7b05dcba0
commit c11d09a885
4 changed files with 58 additions and 2 deletions

View File

@@ -153,6 +153,13 @@ public interface CryptoComponent {
byte[] decryptWithPassword(byte[] ciphertext, String password, byte[] decryptWithPassword(byte[] ciphertext, String password,
@Nullable KeyStoreConfig keyStoreConfig); @Nullable KeyStoreConfig keyStoreConfig);
/**
* Returns true if the given ciphertext was encrypted using a stored key
* to strengthen the password-based key. The validity of the ciphertext is
* not checked.
*/
boolean isEncryptedWithStoredKey(byte[] ciphertext);
/** /**
* Encrypts the given plaintext to the given public key. * Encrypts the given plaintext to the given public key.
*/ */

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.account;
import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyStoreConfig;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.Identity;
@@ -210,13 +211,22 @@ class AccountManagerImpl implements AccountManager {
return null; return null;
} }
byte[] ciphertext = fromHexString(hex); byte[] ciphertext = fromHexString(hex);
KeyStoreConfig keyStoreConfig = databaseConfig.getKeyStoreConfig();
byte[] plaintext = crypto.decryptWithPassword(ciphertext, password, byte[] plaintext = crypto.decryptWithPassword(ciphertext, password,
databaseConfig.getKeyStoreConfig()); keyStoreConfig);
if (plaintext == null) { if (plaintext == null) {
LOG.info("Failed to decrypt database key"); LOG.info("Failed to decrypt database key");
return null; return null;
} }
return new SecretKey(plaintext); SecretKey key = new SecretKey(plaintext);
// If the DB key was encrypted without using a stored key and a stored
// key is now available, re-encrypt the DB key with the stored key
if (keyStoreConfig != null &&
!crypto.isEncryptedWithStoredKey(ciphertext)) {
LOG.info("Re-encrypting database key with stored key");
encryptAndStoreDatabaseKey(key, password);
}
return key;
} }
@Override @Override

View File

@@ -467,6 +467,12 @@ class CryptoComponentImpl implements CryptoComponent {
} }
} }
@Override
public boolean isEncryptedWithStoredKey(byte[] ciphertext) {
return ciphertext.length > 0 &&
ciphertext[0] == PBKDF_FORMAT_SCRYPT_KEYSTORE;
}
@Override @Override
public byte[] encryptToKey(PublicKey publicKey, byte[] plaintext) { public byte[] encryptToKey(PublicKey publicKey, byte[] plaintext) {
try { try {

View File

@@ -118,6 +118,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
oneOf(crypto).decryptWithPassword(encryptedKey, password, oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig); keyStoreConfig);
will(returnValue(key.getBytes())); will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
will(returnValue(true));
}}); }});
storeDatabaseKey(keyFile, encryptedKeyHex); storeDatabaseKey(keyFile, encryptedKeyHex);
@@ -136,6 +138,35 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
} }
@Test
public void testSignInReEncryptsKey() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig);
will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
will(returnValue(false));
oneOf(crypto).encryptWithPassword(key.getBytes(), password,
keyStoreConfig);
will(returnValue(newEncryptedKey));
}});
storeDatabaseKey(keyFile, encryptedKeyHex);
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
assertTrue(accountManager.signIn(password));
assertTrue(accountManager.hasDatabaseKey());
SecretKey decrypted = accountManager.getDatabaseKey();
assertNotNull(decrypted);
assertArrayEquals(key.getBytes(), decrypted.getBytes());
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
}
@Test @Test
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception { public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
storeDatabaseKey(keyFile, encryptedKeyHex); storeDatabaseKey(keyFile, encryptedKeyHex);
@@ -316,6 +347,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
oneOf(crypto).decryptWithPassword(encryptedKey, password, oneOf(crypto).decryptWithPassword(encryptedKey, password,
keyStoreConfig); keyStoreConfig);
will(returnValue(key.getBytes())); will(returnValue(key.getBytes()));
oneOf(crypto).isEncryptedWithStoredKey(encryptedKey);
will(returnValue(true));
oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword, oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword,
keyStoreConfig); keyStoreConfig);
will(returnValue(newEncryptedKey)); will(returnValue(newEncryptedKey));