Daggerization and Kotlinification of SecretStoringUtils

This commit is contained in:
Benoit Marty 2019-09-16 19:19:14 +02:00
parent 1ba8a58219
commit 384dd100e9
8 changed files with 129 additions and 58 deletions

View File

@ -29,6 +29,7 @@ import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.RoomDirectoryService
import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.api.session.signout.SignOutService import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.sync.SyncState
@ -50,7 +51,8 @@ interface Session :
FileService, FileService,
PushRuleService, PushRuleService,
PushersService, PushersService,
InitialSyncProgressService { InitialSyncProgressService,
SecureStorageService {
/** /**
* The params associated to the session * The params associated to the session
@ -87,7 +89,7 @@ interface Session :
/** /**
* This method start the sync thread. * This method start the sync thread.
*/ */
fun startSync(fromForeground : Boolean) fun startSync(fromForeground: Boolean)
/** /**
* This method stop the sync thread. * This method stop the sync thread.

View File

@ -0,0 +1,28 @@
/*
* 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.api.session.securestorage
import java.io.InputStream
import java.io.OutputStream
interface SecureStorageService {
fun securelyStoreObject(any: Any, keyAlias: String, outputStream: OutputStream)
fun <T> loadSecureSecret(inputStream: InputStream, keyAlias: String): T?
}

View File

@ -35,6 +35,7 @@ import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
import javax.inject.Inject
import javax.security.auth.x500.X500Principal import javax.security.auth.x500.X500Principal
@ -72,15 +73,17 @@ import javax.security.auth.x500.X500Principal
* Important: Keys stored in the keystore can be wiped out (depends of the OS version, like for example if you * Important: Keys stored in the keystore can be wiped out (depends of the OS version, like for example if you
* add a pin or change the schema); So you might and with a useless pile of bytes. * add a pin or change the schema); So you might and with a useless pile of bytes.
*/ */
object SecretStoringUtils { internal class SecretStoringUtils @Inject constructor(private val context: Context) {
private const val ANDROID_KEY_STORE = "AndroidKeyStore" companion object {
private const val AES_MODE = "AES/GCM/NoPadding"; private const val ANDROID_KEY_STORE = "AndroidKeyStore"
private const val RSA_MODE = "RSA/ECB/PKCS1Padding" private const val AES_MODE = "AES/GCM/NoPadding"
private const val RSA_MODE = "RSA/ECB/PKCS1Padding"
private const val FORMAT_API_M: Byte = 0 private const val FORMAT_API_M: Byte = 0
private const val FORMAT_1: Byte = 1 private const val FORMAT_1: Byte = 1
private const val FORMAT_2: Byte = 2 private const val FORMAT_2: Byte = 2
}
private val keyStore: KeyStore by lazy { private val keyStore: KeyStore by lazy {
KeyStore.getInstance(ANDROID_KEY_STORE).apply { KeyStore.getInstance(ANDROID_KEY_STORE).apply {
@ -109,13 +112,11 @@ object SecretStoringUtils {
* The secret is encrypted using the following method: AES/GCM/NoPadding * The secret is encrypted using the following method: AES/GCM/NoPadding
*/ */
@Throws(Exception::class) @Throws(Exception::class)
fun securelyStoreString(secret: String, keyAlias: String, context: Context): ByteArray? { fun securelyStoreString(secret: String, keyAlias: String): ByteArray? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return when {
return encryptStringM(secret, keyAlias) Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> encryptStringM(secret, keyAlias)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> encryptStringK(secret, keyAlias)
return encryptStringK(secret, keyAlias, context) else -> encryptForOldDevicesNotGood(secret, keyAlias)
} else {
return encryptForOldDevicesNotGood(secret, keyAlias)
} }
} }
@ -123,33 +124,27 @@ object SecretStoringUtils {
* Decrypt a secret that was encrypted by #securelyStoreString() * Decrypt a secret that was encrypted by #securelyStoreString()
*/ */
@Throws(Exception::class) @Throws(Exception::class)
fun loadSecureSecret(encrypted: ByteArray, keyAlias: String, context: Context): String? { fun loadSecureSecret(encrypted: ByteArray, keyAlias: String): String? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return when {
return decryptStringM(encrypted, keyAlias) Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> decryptStringM(encrypted, keyAlias)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> decryptStringK(encrypted, keyAlias)
return decryptStringK(encrypted, keyAlias, context) else -> decryptForOldDevicesNotGood(encrypted, keyAlias)
} else {
return decryptForOldDevicesNotGood(encrypted, keyAlias)
} }
} }
fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream, context: Context) { fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { when {
saveSecureObjectM(keyAlias, output, any) Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> saveSecureObjectK(keyAlias, output, any)
return saveSecureObjectK(keyAlias, output, any, context) else -> saveSecureObjectOldNotGood(keyAlias, output, any)
} else {
return saveSecureObjectOldNotGood(keyAlias, output, any)
} }
} }
fun <T> loadSecureSecret(inputStream: InputStream, keyAlias: String, context: Context): T? { fun <T> loadSecureSecret(inputStream: InputStream, keyAlias: String): T? {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return when {
return loadSecureObjectM(keyAlias, inputStream) Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> loadSecureObjectM(keyAlias, inputStream)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> loadSecureObjectK(keyAlias, inputStream)
return loadSecureObjectK(keyAlias, inputStream, context) else -> loadSecureObjectOldNotGood(keyAlias, inputStream)
} else {
return loadSecureObjectOldNotGood(keyAlias, inputStream)
} }
} }
@ -182,7 +177,7 @@ object SecretStoringUtils {
Generate a key pair for encryption Generate a key pair for encryption
*/ */
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
fun getOrGenerateKeyPairForAlias(alias: String, context: Context): KeyStore.PrivateKeyEntry { fun getOrGenerateKeyPairForAlias(alias: String): KeyStore.PrivateKeyEntry {
val privateKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.PrivateKeyEntry) val privateKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.PrivateKeyEntry)
if (privateKeyEntry != null) return privateKeyEntry if (privateKeyEntry != null) return privateKeyEntry
@ -234,14 +229,14 @@ object SecretStoringUtils {
} }
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
private fun encryptStringK(text: String, keyAlias: String, context: Context): ByteArray? { private fun encryptStringK(text: String, keyAlias: String): ByteArray? {
//we generate a random symetric key //we generate a random symetric key
val key = ByteArray(16) val key = ByteArray(16)
secureRandom.nextBytes(key) secureRandom.nextBytes(key)
val sKey = SecretKeySpec(key, "AES") val sKey = SecretKeySpec(key, "AES")
//we encrypt this key thanks to the key store //we encrypt this key thanks to the key store
val encryptedKey = rsaEncrypt(keyAlias, key, context) val encryptedKey = rsaEncrypt(keyAlias, key)
val cipher = Cipher.getInstance(AES_MODE) val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, sKey) cipher.init(Cipher.ENCRYPT_MODE, sKey)
@ -286,12 +281,12 @@ object SecretStoringUtils {
} }
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
private fun decryptStringK(data: ByteArray, keyAlias: String, context: Context): String? { private fun decryptStringK(data: ByteArray, keyAlias: String): String? {
val (encryptedKey, iv, encrypted) = format1Extract(ByteArrayInputStream(data)) val (encryptedKey, iv, encrypted) = format1Extract(ByteArrayInputStream(data))
//we need to decrypt the key //we need to decrypt the key
val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey), context) val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey))
val cipher = Cipher.getInstance(AES_MODE) val cipher = Cipher.getInstance(AES_MODE)
val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv) val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec) cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec)
@ -321,14 +316,14 @@ object SecretStoringUtils {
} }
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
private fun saveSecureObjectK(keyAlias: String, output: OutputStream, writeObject: Any, context: Context) { private fun saveSecureObjectK(keyAlias: String, output: OutputStream, writeObject: Any) {
//we generate a random symetric key //we generate a random symetric key
val key = ByteArray(16) val key = ByteArray(16)
secureRandom.nextBytes(key) secureRandom.nextBytes(key)
val sKey = SecretKeySpec(key, "AES") val sKey = SecretKeySpec(key, "AES")
//we encrypt this key thanks to the key store //we encrypt this key thanks to the key store
val encryptedKey = rsaEncrypt(keyAlias, key, context) val encryptedKey = rsaEncrypt(keyAlias, key)
val cipher = Cipher.getInstance(AES_MODE) val cipher = Cipher.getInstance(AES_MODE)
cipher.init(Cipher.ENCRYPT_MODE, sKey) cipher.init(Cipher.ENCRYPT_MODE, sKey)
@ -418,12 +413,12 @@ object SecretStoringUtils {
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
@Throws(IOException::class) @Throws(IOException::class)
private fun <T> loadSecureObjectK(keyAlias: String, inputStream: InputStream, context: Context): T? { private fun <T> loadSecureObjectK(keyAlias: String, inputStream: InputStream): T? {
val (encryptedKey, iv, encrypted) = format1Extract(inputStream) val (encryptedKey, iv, encrypted) = format1Extract(inputStream)
//we need to decrypt the key //we need to decrypt the key
val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey), context) val sKeyBytes = rsaDecrypt(keyAlias, ByteArrayInputStream(encryptedKey))
val cipher = Cipher.getInstance(AES_MODE) val cipher = Cipher.getInstance(AES_MODE)
val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv) val spec = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) IvParameterSpec(iv) else GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec) cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(sKeyBytes, "AES"), spec)
@ -464,8 +459,8 @@ object SecretStoringUtils {
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
@Throws(Exception::class) @Throws(Exception::class)
private fun rsaEncrypt(alias: String, secret: ByteArray, context: Context): ByteArray { private fun rsaEncrypt(alias: String, secret: ByteArray): ByteArray {
val privateKeyEntry = getOrGenerateKeyPairForAlias(alias, context) val privateKeyEntry = getOrGenerateKeyPairForAlias(alias)
// Encrypt the text // Encrypt the text
val inputCipher = Cipher.getInstance(RSA_MODE) val inputCipher = Cipher.getInstance(RSA_MODE)
inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.certificate.publicKey) inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry.certificate.publicKey)
@ -480,8 +475,8 @@ object SecretStoringUtils {
@RequiresApi(Build.VERSION_CODES.KITKAT) @RequiresApi(Build.VERSION_CODES.KITKAT)
@Throws(Exception::class) @Throws(Exception::class)
private fun rsaDecrypt(alias: String, encrypted: InputStream, context: Context): ByteArray { private fun rsaDecrypt(alias: String, encrypted: InputStream): ByteArray {
val privateKeyEntry = getOrGenerateKeyPairForAlias(alias, context) val privateKeyEntry = getOrGenerateKeyPairForAlias(alias)
val output = Cipher.getInstance(RSA_MODE) val output = Cipher.getInstance(RSA_MODE)
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey) output.init(Cipher.DECRYPT_MODE, privateKeyEntry.privateKey)

View File

@ -36,7 +36,8 @@ import javax.inject.Inject
* then we generate a random secret key. The database key is encrypted with the secret key; The secret * 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 * key is encrypted with the public RSA key and stored with the encrypted key in the shared pref
*/ */
internal class RealmKeysUtils @Inject constructor(private val context: Context) { internal class RealmKeysUtils @Inject constructor(context: Context,
private val secretStoringUtils: SecretStoringUtils) {
private val rng = SecureRandom() private val rng = SecureRandom()
@ -65,7 +66,7 @@ internal class RealmKeysUtils @Inject constructor(private val context: Context)
private fun createAndSaveKeyForDatabase(alias: String): ByteArray { private fun createAndSaveKeyForDatabase(alias: String): ByteArray {
val key = generateKeyForRealm() val key = generateKeyForRealm()
val encodedKey = Base64.encodeToString(key, Base64.NO_PADDING) val encodedKey = Base64.encodeToString(key, Base64.NO_PADDING)
val toStore = SecretStoringUtils.securelyStoreString(encodedKey, alias, context) val toStore = secretStoringUtils.securelyStoreString(encodedKey, alias)
sharedPreferences sharedPreferences
.edit() .edit()
.putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore!!, Base64.NO_PADDING)) .putString("${ENCRYPTED_KEY_PREFIX}_$alias", Base64.encodeToString(toStore!!, Base64.NO_PADDING))
@ -80,7 +81,7 @@ internal class RealmKeysUtils @Inject constructor(private val context: Context)
private fun extractKeyForDatabase(alias: String): ByteArray { private fun extractKeyForDatabase(alias: String): ByteArray {
val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null) val encryptedB64 = sharedPreferences.getString("${ENCRYPTED_KEY_PREFIX}_$alias", null)
val encryptedKey = Base64.decode(encryptedB64, Base64.NO_PADDING) val encryptedKey = Base64.decode(encryptedB64, Base64.NO_PADDING)
val b64 = SecretStoringUtils.loadSecureSecret(encryptedKey, alias, context) val b64 = secretStoringUtils.loadSecureSecret(encryptedKey, alias)
return Base64.decode(b64!!, Base64.NO_PADDING) return Base64.decode(b64!!, Base64.NO_PADDING)
} }
@ -104,7 +105,7 @@ internal class RealmKeysUtils @Inject constructor(private val context: Context)
// Delete elements related to the alias // Delete elements related to the alias
fun clear(alias: String) { fun clear(alias: String) {
if (hasKeyForDatabase(alias)) { if (hasKeyForDatabase(alias)) {
SecretStoringUtils.safeDeleteKey(alias) secretStoringUtils.safeDeleteKey(alias)
sharedPreferences sharedPreferences
.edit() .edit()

View File

@ -35,6 +35,7 @@ import im.vector.matrix.android.api.session.group.GroupService
import im.vector.matrix.android.api.session.pushers.PushersService import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.matrix.android.api.session.room.RoomDirectoryService import im.vector.matrix.android.api.session.room.RoomDirectoryService
import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.RoomService
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.api.session.signout.SignOutService import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState import im.vector.matrix.android.api.session.sync.SyncState
@ -63,6 +64,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
private val pushersService: Lazy<PushersService>, private val pushersService: Lazy<PushersService>,
private val cryptoService: Lazy<DefaultCryptoService>, private val cryptoService: Lazy<DefaultCryptoService>,
private val fileService: Lazy<FileService>, private val fileService: Lazy<FileService>,
private val secureStorageService: Lazy<SecureStorageService>,
private val syncThreadProvider: Provider<SyncThread>, private val syncThreadProvider: Provider<SyncThread>,
private val contentUrlResolver: ContentUrlResolver, private val contentUrlResolver: ContentUrlResolver,
private val contentUploadProgressTracker: ContentUploadStateTracker, private val contentUploadProgressTracker: ContentUploadStateTracker,
@ -78,7 +80,8 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
PushRuleService by pushRuleService.get(), PushRuleService by pushRuleService.get(),
PushersService by pushersService.get(), PushersService by pushersService.get(),
FileService by fileService.get(), FileService by fileService.get(),
InitialSyncProgressService by initialSyncProgressService.get() { InitialSyncProgressService by initialSyncProgressService.get(),
SecureStorageService by secureStorageService.get() {
private var isOpen = false private var isOpen = false

View File

@ -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.auth.data.SessionParams
import im.vector.matrix.android.api.session.InitialSyncProgressService import im.vector.matrix.android.api.session.InitialSyncProgressService
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.database.RealmKeysUtils import im.vector.matrix.android.internal.database.RealmKeysUtils
import im.vector.matrix.android.internal.database.model.SessionRealmModule import im.vector.matrix.android.internal.database.model.SessionRealmModule
@ -39,6 +40,7 @@ import im.vector.matrix.android.internal.session.room.EventRelationsAggregationU
import im.vector.matrix.android.internal.session.room.create.RoomCreateEventLiveObserver import im.vector.matrix.android.internal.session.room.create.RoomCreateEventLiveObserver
import im.vector.matrix.android.internal.session.room.prune.EventsPruner import im.vector.matrix.android.internal.session.room.prune.EventsPruner
import im.vector.matrix.android.internal.session.room.tombstone.RoomTombstoneEventLiveObserver import im.vector.matrix.android.internal.session.room.tombstone.RoomTombstoneEventLiveObserver
import im.vector.matrix.android.internal.session.securestorage.DefaultSecureStorageService
import im.vector.matrix.android.internal.util.md5 import im.vector.matrix.android.internal.util.md5
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -166,4 +168,7 @@ internal abstract class SessionModule {
@Binds @Binds
abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService
@Binds
abstract fun bindSecureStorageService(secureStorageService: DefaultSecureStorageService): SecureStorageService
} }

View File

@ -0,0 +1,36 @@
/*
* 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.session.securestorage
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.api.util.SecretStoringUtils
import im.vector.matrix.android.internal.di.UserMd5
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject
internal class DefaultSecureStorageService @Inject constructor(@UserMd5 private val userMd5: String,
private val secretStoringUtils: SecretStoringUtils) : SecureStorageService {
override fun securelyStoreObject(any: Any, keyAlias: String, outputStream: OutputStream) {
secretStoringUtils.securelyStoreObject(any, "${userMd5}_$keyAlias", outputStream)
}
override fun <T> loadSecureSecret(inputStream: InputStream, keyAlias: String): T? {
return secretStoringUtils.loadSecureSecret(inputStream, "${userMd5}_$keyAlias")
}
}

View File

@ -24,7 +24,6 @@ import androidx.annotation.WorkerThread
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.Person import androidx.core.app.Person
import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.matrix.android.api.util.SecretStoringUtils
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
@ -448,7 +447,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME) val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (!file.exists()) file.createNewFile() if (!file.exists()) file.createNewFile()
FileOutputStream(file).use { FileOutputStream(file).use {
SecretStoringUtils.securelyStoreObject(eventList, "notificationMgr", it, this.context) activeSessionHolder.getSafeActiveSession()?.securelyStoreObject(eventList, KEY_ALIAS_SECRET_STORAGE, it)
} }
} catch (e: Throwable) { } catch (e: Throwable) {
Timber.e(e, "## Failed to save cached notification info") Timber.e(e, "## Failed to save cached notification info")
@ -461,7 +460,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME) val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (file.exists()) { if (file.exists()) {
FileInputStream(file).use { FileInputStream(file).use {
val events: ArrayList<NotifiableEvent>? = SecretStoringUtils.loadSecureSecret(it, "notificationMgr", this.context) val events: ArrayList<NotifiableEvent>? = activeSessionHolder.getSafeActiveSession()?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
if (events != null) { if (events != null) {
return ArrayList(events.mapNotNull { it as? NotifiableEvent }) return ArrayList(events.mapNotNull { it as? NotifiableEvent })
} }
@ -486,5 +485,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
private const val ROOM_EVENT_NOTIFICATION_ID = 2 private const val ROOM_EVENT_NOTIFICATION_ID = 2
private const val ROOMS_NOTIFICATIONS_FILE_NAME = "im.vector.notifications.cache" private const val ROOMS_NOTIFICATIONS_FILE_NAME = "im.vector.notifications.cache"
private const val KEY_ALIAS_SECRET_STORAGE = "notificationMgr"
} }
} }