diff --git a/vector/src/main/java/im/vector/riotredesign/core/utils/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/SecretStoringUtils.kt similarity index 99% rename from vector/src/main/java/im/vector/riotredesign/core/utils/SecretStoringUtils.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/SecretStoringUtils.kt index 1cbb28aeab..6dc0d789cc 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/utils/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/SecretStoringUtils.kt @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.riotredesign.core.utils +package im.vector.matrix.android.api.util import android.content.Context import android.os.Build 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 472d653dee..2459c3546a 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,8 +23,8 @@ 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.di.AuthDatabase -import im.vector.matrix.android.internal.di.MatrixScope import io.realm.RealmConfiguration import java.io.File @@ -42,6 +42,7 @@ internal abstract class AuthModule { old.renameTo(File(context.filesDir, "matrix-sdk-auth.realm")) } return RealmConfiguration.Builder() + .configureEncryption("matrix-sdk-auth", context) .name("matrix-sdk-auth.realm") .modules(AuthRealmModule()) .deleteRealmIfMigrationNeeded() @@ -50,7 +51,6 @@ internal abstract class AuthModule { } - @Binds abstract fun bindSessionParamsStore(sessionParamsStore: RealmSessionParamsStore): SessionParamsStore 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 89baf1c6b1..7b1bc00b47 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 @@ -31,6 +31,7 @@ import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreMigrati import im.vector.matrix.android.internal.crypto.store.db.RealmCryptoStoreModule import im.vector.matrix.android.internal.crypto.store.db.hash import im.vector.matrix.android.internal.crypto.tasks.* +import im.vector.matrix.android.internal.database.configureEncryption 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 @@ -45,14 +46,16 @@ internal abstract class CryptoModule { @Module companion object { - // Realm configuration, named to avoid clash with main cache realm configuration @JvmStatic @Provides @CryptoDatabase @SessionScope fun providesRealmConfiguration(context: Context, credentials: Credentials): RealmConfiguration { + val userIDHash = credentials.userId.hash() + return RealmConfiguration.Builder() - .directory(File(context.filesDir, credentials.userId.hash())) + .directory(File(context.filesDir, userIDHash)) + .configureEncryption("crypto_module_$userIDHash", context) .name("crypto_store.realm") .modules(RealmCryptoStoreModule()) .schemaVersion(RealmCryptoStoreMigration.CRYPTO_STORE_SCHEMA_VERSION) @@ -169,6 +172,4 @@ internal abstract class CryptoModule { @Binds abstract fun bindDeleteDeviceWithUserPasswordTask(deleteDeviceWithUserPasswordTask: DefaultDeleteDeviceWithUserPasswordTask): DeleteDeviceWithUserPasswordTask - - } 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 new file mode 100644 index 0000000000..bdfa442916 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmKeysUtils.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.internal.database + +import android.content.Context +import android.util.Base64 +import im.vector.matrix.android.api.util.SecretStoringUtils +import io.realm.RealmConfiguration +import timber.log.Timber +import java.security.SecureRandom + + +object RealmKeysUtils { + + + private val ENCRYPTED_KEY_PREFIX = "REALM_ENCR_KEY" + + private val rng = SecureRandom() + + private fun generateKeyForRealm(): ByteArray { + val keyForRealm = ByteArray(RealmConfiguration.KEY_LENGTH) + rng.nextBytes(keyForRealm) + return keyForRealm + } + + /** + * Check if there is already a key for this alias + */ + fun hasKeyForDatabase(alias: String, context: Context): Boolean { + val sharedPreferences = getSharedPreferences(context) + return sharedPreferences.contains("${ENCRYPTED_KEY_PREFIX}_$alias") + } + + /** + * Creates a new secure random key for this database. + * 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) + */ + fun createAndSaveKeyForDatabase(alias: String, context: Context): 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)) + .apply() + return key + } + + /** + * Retrieves the key for this database + * throws if something goes wrong + */ + fun extractKeyForDatabase(alias: String, context: Context): ByteArray { + val sharedPreferences = getSharedPreferences(context) + val encrytpedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null) + val encryptedKey = Base64.decode(encrytpedB64, 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.riotx-sdk", 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) + } + } else { + Timber.i("Create key for DB alias:$alias") + RealmKeysUtils.createAndSaveKeyForDatabase(alias, context).also { + this.encryptionKey(it) + } + } + 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 10d4abc971..1a3abc409c 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 @@ -27,6 +27,7 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.auth.data.SessionParams 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.model.SessionRealmModule import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.di.SessionDatabase @@ -74,6 +75,7 @@ internal abstract class SessionModule { return RealmConfiguration.Builder() .directory(directory) .name("disk_store.realm") + .configureEncryption("session_db_$childPath", context) .modules(SessionRealmModule()) .deleteRealmIfMigrationNeeded() .build() diff --git a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt index 8c81570b7e..a66d6395cf 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/notifications/NotificationDrawerManager.kt @@ -21,10 +21,10 @@ import android.graphics.Bitmap import androidx.core.app.NotificationCompat import androidx.core.app.Person import im.vector.matrix.android.api.session.content.ContentUrlResolver +import im.vector.matrix.android.api.util.SecretStoringUtils import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.R import im.vector.riotredesign.core.di.ActiveSessionHolder -import im.vector.riotredesign.core.utils.SecretStoringUtils import im.vector.riotredesign.features.settings.PreferencesManager import me.gujun.android.span.span import timber.log.Timber