diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt index 2459c3546a..51367ab3f3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt @@ -23,7 +23,7 @@ import dagger.Provides import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.internal.auth.db.AuthRealmModule import im.vector.matrix.android.internal.auth.db.RealmSessionParamsStore -import im.vector.matrix.android.internal.database.configureEncryption +import im.vector.matrix.android.internal.database.RealmKeysUtils import im.vector.matrix.android.internal.di.AuthDatabase import io.realm.RealmConfiguration import java.io.File @@ -36,13 +36,16 @@ internal abstract class AuthModule { @JvmStatic @Provides @AuthDatabase - fun providesRealmConfiguration(context: Context): RealmConfiguration { + fun providesRealmConfiguration(context: Context, realmKeysUtils: RealmKeysUtils): RealmConfiguration { val old = File(context.filesDir, "matrix-sdk-auth") if (old.exists()) { old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm")) } + return RealmConfiguration.Builder() - .configureEncryption("matrix-sdk-auth", context) + .apply { + realmKeysUtils.configureEncryption(this, "matrix-sdk-auth") + } .name("matrix-sdk-auth.realm") .modules(AuthRealmModule()) .deleteRealmIfMigrationNeeded() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt index 4272dbd340..bf82cc6131 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/CryptoModule.kt @@ -30,7 +30,7 @@ import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStore import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigration import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule import im.vector.matrix.android.internal.crypto.tasks.* -import im.vector.matrix.android.internal.database.configureEncryption +import im.vector.matrix.android.internal.database.RealmKeysUtils import im.vector.matrix.android.internal.di.CryptoDatabase import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.cache.ClearCacheTask @@ -50,12 +50,14 @@ internal abstract class CryptoModule { @Provides @CryptoDatabase @SessionScope - fun providesRealmConfiguration(context: Context, credentials: Credentials): RealmConfiguration { + fun providesRealmConfiguration(context: Context, credentials: Credentials, realmKeysUtils: RealmKeysUtils): RealmConfiguration { val userIDHash = credentials.userId.md5() return RealmConfiguration.Builder() .directory(File(context.filesDir, userIDHash)) - .configureEncryption("crypto_module_$userIDHash", context) + .apply { + realmKeysUtils.configureEncryption(this, "crypto_module_$userIDHash") + } .name("crypto_store.realm") .modules(RealmCryptoStoreModule()) .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt index ee8ee41821..03ff641cf7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt @@ -17,10 +17,12 @@ package im.vector.matrix.android.internal.database import android.content.Context import android.util.Base64 +import im.vector.matrix.android.BuildConfig import im.vector.matrix.android.api.util.SecretStoringUtils import io.realm.RealmConfiguration import timber.log.Timber import java.security.SecureRandom +import javax.inject.Inject /** * On creation a random key is generated, this key is then encrypted using the system KeyStore. @@ -34,12 +36,12 @@ import java.security.SecureRandom * then we generate a random secret key. The database key is encrypted with the secret key; The secret * key is encrypted with the public RSA key and stored with the encrypted key in the shared pref */ -private object RealmKeysUtils { - - private const val ENCRYPTED_KEY_PREFIX = "REALM_ENCRYPTED_KEY" +internal class RealmKeysUtils @Inject constructor(private val context: Context) { private val rng = SecureRandom() + private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.keys", Context.MODE_PRIVATE) + private fun generateKeyForRealm(): ByteArray { val keyForRealm = ByteArray(RealmConfiguration.KEY_LENGTH) rng.nextBytes(keyForRealm) @@ -49,8 +51,7 @@ private object RealmKeysUtils { /** * Check if there is already a key for this alias */ - fun hasKeyForDatabase(alias: String, context: Context): Boolean { - val sharedPreferences = getSharedPreferences(context) + private fun hasKeyForDatabase(alias: String): Boolean { return sharedPreferences.contains("${ENCRYPTED_KEY_PREFIX}_$alias") } @@ -59,13 +60,12 @@ private object RealmKeysUtils { * The random key is then encrypted by the keystore, and the encrypted key is stored * in shared preferences. * - * @return the generate key (can be passed to Realm Configuration) + * @return the generated key (can be passed to Realm Configuration) */ - fun createAndSaveKeyForDatabase(alias: String, context: Context): ByteArray { + private fun createAndSaveKeyForDatabase(alias: String): ByteArray { val key = generateKeyForRealm() val encodedKey = Base64.encodeToString(key, Base64.NO_PADDING) val toStore = SecretStoringUtils.securelyStoreString(encodedKey, alias, context) - val sharedPreferences = getSharedPreferences(context) sharedPreferences .edit() .putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore!!, Base64.NO_PADDING)) @@ -77,30 +77,31 @@ private object RealmKeysUtils { * Retrieves the key for this database * throws if something goes wrong */ - fun extractKeyForDatabase(alias: String, context: Context): ByteArray { - val sharedPreferences = getSharedPreferences(context) + private fun extractKeyForDatabase(alias: String): ByteArray { val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null) val encryptedKey = Base64.decode(encryptedB64, Base64.NO_PADDING) val b64 = SecretStoringUtils.loadSecureSecret(encryptedKey, alias, context) return Base64.decode(b64!!, Base64.NO_PADDING) } - private fun getSharedPreferences(context: Context) = - context.getSharedPreferences("im.vector.matrix.android.keys", Context.MODE_PRIVATE) -} - - -fun RealmConfiguration.Builder.configureEncryption(alias: String, context: Context): RealmConfiguration.Builder { - if (RealmKeysUtils.hasKeyForDatabase(alias, context)) { - Timber.i("Found key for alias:$alias") - RealmKeysUtils.extractKeyForDatabase(alias, context).also { - this.encryptionKey(it) + fun configureEncryption(realmConfigurationBuilder: RealmConfiguration.Builder, alias: String) { + val key = if (hasKeyForDatabase(alias)) { + Timber.i("Found key for alias:$alias") + extractKeyForDatabase(alias) + } else { + Timber.i("Create key for DB alias:$alias") + createAndSaveKeyForDatabase(alias) } - } else { - Timber.i("Create key for DB alias:$alias") - RealmKeysUtils.createAndSaveKeyForDatabase(alias, context).also { - this.encryptionKey(it) + + if (BuildConfig.LOG_PRIVATE_DATA) { + val log = key.joinToString("") { "%02x".format(it) } + Timber.w("Database key for alias `$alias`: $log") } + + realmConfigurationBuilder.encryptionKey(key) + } + + companion object { + private const val ENCRYPTED_KEY_PREFIX = "REALM_ENCRYPTED_KEY" } - return this } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 7570d50b9c..9aa0365e28 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -28,7 +28,7 @@ import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.InitialSyncProgressService import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.internal.database.LiveEntityObserver -import im.vector.matrix.android.internal.database.configureEncryption +import im.vector.matrix.android.internal.database.RealmKeysUtils import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.di.SessionDatabase @@ -70,14 +70,16 @@ internal abstract class SessionModule { @Provides @SessionDatabase @SessionScope - fun providesRealmConfiguration(sessionParams: SessionParams, context: Context): RealmConfiguration { + fun providesRealmConfiguration(sessionParams: SessionParams, realmKeysUtils: RealmKeysUtils, context: Context): RealmConfiguration { val childPath = sessionParams.credentials.userId.md5() val directory = File(context.filesDir, childPath) return RealmConfiguration.Builder() .directory(directory) .name("disk_store.realm") - .configureEncryption("session_db_$childPath", context) + .apply { + realmKeysUtils.configureEncryption(this, "session_db_$childPath") + } .modules(SessionRealmModule()) .deleteRealmIfMigrationNeeded() .build()