diff --git a/CHANGES.md b/CHANGES.md index 651a732f27..74269178dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ Improvements 🙌: - Verification DM / Handle concurrent .start after .ready (#794) - Cross-Signing | Update Shield Logic for DM (#963) - Cross-Signing | Complete security new session design update (#1135) + - Cross-Signing | Setup key backup as part of SSSS bootstrapping (#1201) + - Cross-Signing | Gossip key backup recovery key (#1200) Bugfix 🐛: - Missing avatar/displayname after verification request message (#841) diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt index aec5e6c423..7ac92ed74c 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt @@ -34,6 +34,8 @@ import im.vector.matrix.android.common.TestConstants import im.vector.matrix.android.internal.crypto.GossipingRequestState import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestState import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel +import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo +import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent @@ -197,6 +199,16 @@ class KeyShareTests : InstrumentedTest { ), it) } + // Also bootstrap keybackup on first session + val creationInfo = mTestHelper.doSync { + aliceSession1.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it) + } + val version = mTestHelper.doSync { + aliceSession1.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it) + } + // Save it for gossiping + aliceSession1.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version) + val aliceSession2 = mTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true)) val aliceVerificationService1 = aliceSession1.cryptoService().verificationService() @@ -260,9 +272,18 @@ class KeyShareTests : InstrumentedTest { mTestHelper.waitWithLatch(60_000) { latch -> mTestHelper.retryPeriodicallyWithLatch(latch) { - Log.d("#TEST", "CAN XS :${ aliceSession2.cryptoService().crossSigningService().getMyCrossSigningKeys()}") + Log.d("#TEST", "CAN XS :${aliceSession2.cryptoService().crossSigningService().getMyCrossSigningKeys()}") aliceSession2.cryptoService().crossSigningService().canCrossSign() } } + + // Test that key backup key has been shared to + mTestHelper.waitWithLatch(60_000) { latch -> + val keysBackupService = aliceSession2.cryptoService().keysBackupService() + mTestHelper.retryPeriodicallyWithLatch(latch) { + Log.d("#TEST", "Recovery :${ keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey}") + keysBackupService.getKeyBackupRecoveryKeyInfo()?.recoveryKey != creationInfo.recoveryKey + } + } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/crosssigning/CrossSigningSsssSecretConstants.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/crosssigning/CrossSigningSsssSecretConstants.kt index d46a724463..2c3425bcb4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/crosssigning/CrossSigningSsssSecretConstants.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/crosssigning/CrossSigningSsssSecretConstants.kt @@ -21,3 +21,5 @@ const val MASTER_KEY_SSSS_NAME = "m.cross_signing.master" const val USER_SIGNING_KEY_SSSS_NAME = "m.cross_signing.user_signing" const val SELF_SIGNING_KEY_SSSS_NAME = "m.cross_signing.self_signing" + +const val KEYBACKUP_SECRET_SSSS_NAME = "m.megolm_backup.v1" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt index cb06dbf665..e9ed36ba23 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/keysbackup/KeysBackupService.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCre import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult +import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo interface KeysBackupService { /** @@ -172,6 +173,8 @@ interface KeysBackupService { password: String, callback: MatrixCallback) + fun onSecretKeyGossip(secret: String) + /** * Restore a backup with a recovery key from a given backup version stored on the homeserver. * @@ -210,4 +213,8 @@ interface KeysBackupService { val isEnabled: Boolean val isStucked: Boolean val state: KeysBackupState + + // For gossiping + fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) + fun getKeyBackupRecoveryKeyInfo() : SavedKeyBackupKeyInfo? } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index d3e5ada8cb..ee96e45e85 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -33,6 +33,7 @@ import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.listeners.ProgressListener import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.crypto.MXCryptoError +import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener @@ -239,7 +240,7 @@ internal class DefaultCryptoService @Inject constructor( override fun getDevicesList(callback: MatrixCallback) { getDevicesTask .configureWith { -// this.executionThread = TaskThread.CRYPTO + // this.executionThread = TaskThread.CRYPTO this.callback = callback } .executeBy(taskExecutor) @@ -635,7 +636,7 @@ internal class DefaultCryptoService @Inject constructor( */ @Throws(MXCryptoError::class) override fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult { - return internalDecryptEvent(event, timeline) + return internalDecryptEvent(event, timeline) } /** @@ -766,19 +767,30 @@ internal class DefaultCryptoService @Inject constructor( return } - when (existingRequest.secretName) { + if (!handleSDKLevelGossip(existingRequest.secretName, secretContent.secretValue)) { + // TODO Ask to application layer? + Timber.v("## onSecretSend() : secret not handled by SDK") + } + } + + /** + * Returns true if handled by SDK, otherwise should be sent to application layer + */ + private fun handleSDKLevelGossip(secretName: String?, secretValue: String): Boolean { + return when (secretName) { SELF_SIGNING_KEY_SSSS_NAME -> { - crossSigningService.onSecretSSKGossip(secretContent.secretValue) - return + crossSigningService.onSecretSSKGossip(secretValue) + true } USER_SIGNING_KEY_SSSS_NAME -> { - crossSigningService.onSecretUSKGossip(secretContent.secretValue) - return + crossSigningService.onSecretUSKGossip(secretValue) + true } - else -> { - // Ask to application layer? - Timber.v("## onSecretSend() : secret not handled by SDK") + KEYBACKUP_SECRET_SSSS_NAME -> { + keysBackupService.onSecretKeyGossip(secretValue) + true } + else -> false } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt index 8bec87b341..da596960dd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt @@ -17,14 +17,16 @@ package im.vector.matrix.android.internal.crypto import im.vector.matrix.android.api.auth.data.Credentials -import im.vector.matrix.android.api.auth.data.sessionId import im.vector.matrix.android.api.crypto.MXCryptoConfig +import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.keyshare.GossipingRequestListener import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.internal.crypto.crosssigning.toBase64NoPadding +import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import im.vector.matrix.android.internal.crypto.model.rest.GossipingDefaultContent import im.vector.matrix.android.internal.crypto.model.rest.GossipingToDeviceObject import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore @@ -281,6 +283,10 @@ internal class IncomingGossipingRequestManager @Inject constructor( when (secretName) { SELF_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.selfSigned USER_SIGNING_KEY_SSSS_NAME -> cryptoStore.getCrossSigningPrivateKeys()?.user + KEYBACKUP_SECRET_SSSS_NAME -> cryptoStore.getKeyBackupRecoveryKeyInfo()?.recoveryKey + ?.let { + extractCurveKeyFromRecoveryKey(it)?.toBase64NoPadding() + } else -> null }?.let { secretValue -> Timber.i("## GOSSIP processIncomingSecretShareRequest() : Sharing secret $secretName with $device locally trusted") @@ -301,6 +307,8 @@ internal class IncomingGossipingRequestManager @Inject constructor( return } + Timber.v("## GOSSIP processIncomingSecretShareRequest() : $secretName unknown at SDK level, asking to app layer") + request.ignore = Runnable { cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt index 3ec5a2f979..75e37d27f6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/keysbackup/DefaultKeysBackupService.kt @@ -36,6 +36,7 @@ import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MegolmSessionData import im.vector.matrix.android.internal.crypto.ObjectSigner import im.vector.matrix.android.internal.crypto.actions.MegolmSessionDataImporter +import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64 import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrust import im.vector.matrix.android.internal.crypto.keysbackup.model.KeysBackupVersionTrustSignature import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupAuthData @@ -67,6 +68,7 @@ import im.vector.matrix.android.internal.crypto.keysbackup.util.extractCurveKeyF import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.OlmInboundGroupSessionWrapper import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore +import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo import im.vector.matrix.android.internal.crypto.store.db.model.KeysBackupDataEntity import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.UserId @@ -580,6 +582,31 @@ internal class DefaultKeysBackupService @Inject constructor( } } + override fun onSecretKeyGossip(secret: String) { + Timber.i("## CrossSigning - onSecretKeyGossip") + + cryptoCoroutineScope.launch(coroutineDispatchers.main) { + try { + val keysBackupVersion = getKeysBackupLastVersionTask.execute(Unit) + val recoveryKey = computeRecoveryKey(secret.fromBase64()) + if (isValidRecoveryKeyForKeysBackupVersion(recoveryKey, keysBackupVersion)) { + awaitCallback { + trustKeysBackupVersion(keysBackupVersion, true, it) + } + val importResult = awaitCallback { + restoreKeysWithRecoveryKey(keysBackupVersion, recoveryKey, null, null, null, it) + } + cryptoStore.saveBackupRecoveryKey(recoveryKey, keysBackupVersion.version) + Timber.i("onSecretKeyGossip: Recovered keys ${importResult.successfullyNumberOfImportedKeys} out of ${importResult.totalNumberOfKeys}") + } else { + Timber.e("onSecretKeyGossip: Recovery key is not valid ${keysBackupVersion.version}") + } + } catch (failure: Throwable) { + Timber.e("onSecretKeyGossip: failed to trust key backup version ${keysBackupVersion?.version}") + } + } + } + /** * Get public key from a Recovery key * @@ -1391,6 +1418,14 @@ internal class DefaultKeysBackupService @Inject constructor( .executeBy(taskExecutor) } + override fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? { + return cryptoStore.getKeyBackupRecoveryKeyInfo() + } + + override fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) { + cryptoStore.saveBackupRecoveryKey(recoveryKey, version) + } + companion object { // Maximum delay in ms in {@link maybeBackupKeys} private const val KEY_BACKUP_WAITING_TIME_TO_SEND_KEY_BACKUP_MILLIS = 10_000L diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index 726d56a2f7..a8f65e9219 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -405,6 +405,9 @@ internal interface IMXCryptoStore { fun getCrossSigningPrivateKeys(): PrivateKeysInfo? + fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) + fun getKeyBackupRecoveryKeyInfo() : SavedKeyBackupKeyInfo? + fun setUserKeysAsTrusted(userId: String, trusted: Boolean = true) fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified: Boolean) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/SavedKeyBackupKeyInfo.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/SavedKeyBackupKeyInfo.kt new file mode 100644 index 0000000000..fda9bb1d72 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/SavedKeyBackupKeyInfo.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 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.crypto.store + +data class SavedKeyBackupKeyInfo( + val recoveryKey : String, + val version: String +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index 7f136df54d..bd51cf8539 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -45,6 +45,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.RoomKeyRequestBody import im.vector.matrix.android.internal.crypto.model.toEntity import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.PrivateKeysInfo +import im.vector.matrix.android.internal.crypto.store.SavedKeyBackupKeyInfo import im.vector.matrix.android.internal.crypto.store.db.model.CrossSigningInfoEntity import im.vector.matrix.android.internal.crypto.store.db.model.CrossSigningInfoEntityFields import im.vector.matrix.android.internal.crypto.store.db.model.CryptoMapper @@ -216,8 +217,8 @@ internal class RealmCryptoStore @Inject constructor( override fun getOrCreateOlmAccount(): OlmAccount { doRealmTransaction(realmConfiguration) { - val metaData = it.where().findFirst() - val existing = metaData!!.getOlmAccount() + val metaData = it.where().findFirst() + val existing = metaData!!.getOlmAccount() if (existing == null) { Timber.d("## Crypto Creating olm account") val created = OlmAccount() @@ -389,6 +390,29 @@ internal class RealmCryptoStore @Inject constructor( } } + override fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) { + doRealmTransaction(realmConfiguration) { realm -> + realm.where().findFirst()?.apply { + keyBackupRecoveryKey = recoveryKey + keyBackupRecoveryKeyVersion = version + } + } + } + + override fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? { + return doRealmQueryAndCopy(realmConfiguration) { realm -> + realm.where().findFirst() + }?.let { + val key = it.keyBackupRecoveryKey + val version = it.keyBackupRecoveryKeyVersion + if (!key.isNullOrBlank() && !version.isNullOrBlank()) { + SavedKeyBackupKeyInfo(recoveryKey = key, version = version) + } else { + null + } + } + } + override fun storeSSKPrivateKey(ssk: String?) { doRealmTransaction(realmConfiguration) { realm -> realm.where().findFirst()?.apply { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt index 588ae3f9c5..d5972b5686 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStoreMigration.kt @@ -37,13 +37,14 @@ import timber.log.Timber internal object RealmCryptoStoreMigration : RealmMigration { // Version 1L added Cross Signing info persistence - const val CRYPTO_STORE_SCHEMA_VERSION = 2L + const val CRYPTO_STORE_SCHEMA_VERSION = 3L override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.v("Migrating Realm Crypto from $oldVersion to $newVersion") if (oldVersion <= 0) migrateTo1(realm) if (oldVersion <= 1) migrateTo2(realm) + if (oldVersion <= 2) migrateTo3(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -185,4 +186,11 @@ internal object RealmCryptoStoreMigration : RealmMigration { .addIndex(OutgoingGossipingRequestEntityFields.TYPE_STR) .addField(OutgoingGossipingRequestEntityFields.REQUEST_STATE_STR, String::class.java) } + + private fun migrateTo3(realm: DynamicRealm) { + Timber.d("Updating CryptoMetadataEntity table") + realm.schema.get("CryptoMetadataEntity") + ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY, String::class.java) + ?.addField(CryptoMetadataEntityFields.KEY_BACKUP_RECOVERY_KEY_VERSION, String::class.java) + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt index 8a2c2914da..2d4706ba76 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/model/CryptoMetadataEntity.kt @@ -38,7 +38,9 @@ internal open class CryptoMetadataEntity( var xSignMasterPrivateKey: String? = null, var xSignUserPrivateKey: String? = null, - var xSignSelfSignedPrivateKey: String? = null + var xSignSelfSignedPrivateKey: String? = null, + var keyBackupRecoveryKey: String? = null, + var keyBackupRecoveryKeyVersion: String? = null // var crossSigningInfoEntity: CrossSigningInfoEntity? = null ) : RealmObject() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt index 973b9944cb..5b8191fc99 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.crypto.verification import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.crypto.crosssigning.CrossSigningService +import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction @@ -103,6 +104,7 @@ internal abstract class DefaultVerificationTransaction( if (otherUserId == userId && !crossSigningService.canCrossSign()) { outgoingGossipingRequestManager.sendSecretShareRequest(SELF_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))) outgoingGossipingRequestManager.sendSecretShareRequest(USER_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))) + outgoingGossipingRequestManager.sendSecretShareRequest(KEYBACKUP_SECRET_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))) } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt index 2571ef674b..a19604d78e 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/recover/BootstrapCrossSigningTask.kt @@ -27,6 +27,8 @@ import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageSer import im.vector.matrix.android.api.session.securestorage.SsssKeyCreationInfo import im.vector.matrix.android.internal.auth.data.LoginFlowTypes import im.vector.matrix.android.internal.auth.registration.RegistrationFlowResponse +import im.vector.matrix.android.internal.crypto.keysbackup.model.MegolmBackupCreationInfo +import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersion import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.awaitCallback @@ -36,6 +38,7 @@ import im.vector.riotx.core.resources.StringProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.launch +import timber.log.Timber import java.util.UUID import javax.inject.Inject @@ -195,7 +198,24 @@ class BootstrapCrossSigningTask @Inject constructor( return BootstrapResult.FailedToStorePrivateKeyInSSSS(failure) } - // TODO configure key backup? + params.progressListener?.onProgress( + WaitingViewData( + stringProvider.getString(R.string.bootstrap_crosssigning_progress_key_backup), + isIndeterminate = true + ) + ) + try { + val creationInfo = awaitCallback { + session.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it) + } + val version = awaitCallback { + session.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it) + } + // Save it for gossiping + session.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version) + } catch (failure: Throwable) { + Timber.e("## BootstrapCrossSigningTask: Failed to init keybackup") + } return BootstrapResult.Success(keyInfo) } diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index c850316912..29e57d1133 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -71,6 +71,7 @@ Synchronizing Master key Synchronizing User key Synchronizing Self Signing key + Setting Up Key Backup