diff --git a/changelog.d/5906.bugfix b/changelog.d/5906.bugfix
new file mode 100644
index 0000000000..be1379c6e4
--- /dev/null
+++ b/changelog.d/5906.bugfix
@@ -0,0 +1 @@
+Desynchronized 4S | Megolm backup causing Unusable backup
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
index 219a328cfd..7127c8d3f4 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupVersionTrustSignature.kt
@@ -16,25 +16,35 @@
 
 package org.matrix.android.sdk.api.session.crypto.keysbackup
 
+import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
 import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
 
 /**
  * A signature in a `KeysBackupVersionTrust` object.
  */
-data class KeysBackupVersionTrustSignature(
-        /**
-         * The id of the device that signed the backup version.
-         */
-        val deviceId: String?,
 
-        /**
-         * The device that signed the backup version.
-         * Can be null if the device is not known.
-         */
-        val device: CryptoDeviceInfo?,
+sealed class KeysBackupVersionTrustSignature {
 
-        /**
-         * Flag to indicate the signature from this device is valid.
-         */
-        val valid: Boolean,
-)
+    data class DeviceSignature(
+            /**
+             * The id of the device that signed the backup version.
+             */
+            val deviceId: String?,
+
+            /**
+             * The device that signed the backup version.
+             * Can be null if the device is not known.
+             */
+            val device: CryptoDeviceInfo?,
+
+            /**
+             * Flag to indicate the signature from this device is valid.
+             */
+            val valid: Boolean) : KeysBackupVersionTrustSignature()
+
+    data class UserSignature(
+            val keyId: String?,
+            val cryptoCrossSigningKey: CryptoCrossSigningKey?,
+            val valid: Boolean
+    ) : KeysBackupVersionTrustSignature()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
new file mode 100644
index 0000000000..311e0ba822
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/CrossSigningOlm.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.crypto.crosssigning
+
+import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
+import org.matrix.android.sdk.internal.session.SessionScope
+import org.matrix.android.sdk.internal.util.JsonCanonicalizer
+import org.matrix.olm.OlmPkSigning
+import org.matrix.olm.OlmUtility
+import javax.inject.Inject
+
+/**
+ * Holds the OlmPkSigning for cross signing.
+ * Can be injected without having to get the full cross signing service
+ */
+@SessionScope
+internal class CrossSigningOlm @Inject constructor(
+        private val cryptoStore: IMXCryptoStore,
+) {
+
+    enum class KeyType {
+        SELF,
+        USER,
+        MASTER
+    }
+
+    var olmUtility: OlmUtility = OlmUtility()
+
+    var masterPkSigning: OlmPkSigning? = null
+    var userPkSigning: OlmPkSigning? = null
+    var selfSigningPkSigning: OlmPkSigning? = null
+
+    fun release() {
+        olmUtility.releaseUtility()
+        listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
+    }
+
+    fun signObject(type: KeyType, strToSign: String): Map<String, String> {
+        val myKeys = cryptoStore.getMyCrossSigningInfo()
+        val pubKey = when (type) {
+            KeyType.SELF   -> myKeys?.selfSigningKey()
+            KeyType.USER   -> myKeys?.userKey()
+            KeyType.MASTER -> myKeys?.masterKey()
+        }?.unpaddedBase64PublicKey
+        val pkSigning = when (type) {
+            KeyType.SELF   -> selfSigningPkSigning
+            KeyType.USER   -> userPkSigning
+            KeyType.MASTER -> masterPkSigning
+        }
+        if (pubKey == null || pkSigning == null) {
+            throw Throwable("Cannot sign from this account, public and/or privateKey Unknown $type|$pkSigning")
+        }
+        val signature = pkSigning.sign(strToSign)
+        return mapOf(
+                "ed25519:$pubKey" to signature
+        )
+    }
+
+    fun verifySignature(type: KeyType, signable: JsonDict, signatures: Map<String, Map<String, String>>) {
+        val myKeys = cryptoStore.getMyCrossSigningInfo()
+                ?: throw NoSuchElementException("Cross Signing not configured")
+        val myUserID = myKeys.userId
+        val pubKey = when (type) {
+            KeyType.SELF   -> myKeys.selfSigningKey()
+            KeyType.USER   -> myKeys.userKey()
+            KeyType.MASTER -> myKeys.masterKey()
+        }?.unpaddedBase64PublicKey ?: throw NoSuchElementException("Cross Signing not configured")
+        val signaturesMadeByMyKey = signatures[myUserID] // Signatures made by me
+                ?.get("ed25519:$pubKey")
+
+        if (signaturesMadeByMyKey.isNullOrBlank()) {
+            throw IllegalArgumentException("Not signed with my key $type")
+        }
+
+        // Check that Alice USK signature of Bob MSK is valid
+        olmUtility.verifyEd25519Signature(signaturesMadeByMyKey, pubKey, JsonCanonicalizer.getCanonicalJson(Map::class.java, signable))
+    }
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
index b8cdc922cc..f4b389846c 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/crosssigning/DefaultCrossSigningService.kt
@@ -54,7 +54,6 @@ import org.matrix.android.sdk.internal.util.JsonCanonicalizer
 import org.matrix.android.sdk.internal.util.logLimit
 import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
 import org.matrix.olm.OlmPkSigning
-import org.matrix.olm.OlmUtility
 import timber.log.Timber
 import java.util.concurrent.TimeUnit
 import javax.inject.Inject
@@ -72,19 +71,13 @@ internal class DefaultCrossSigningService @Inject constructor(
         private val cryptoCoroutineScope: CoroutineScope,
         private val workManagerProvider: WorkManagerProvider,
         private val outgoingKeyRequestManager: OutgoingKeyRequestManager,
+        private val crossSigningOlm: CrossSigningOlm,
         private val updateTrustWorkerDataRepository: UpdateTrustWorkerDataRepository
 ) : CrossSigningService,
         DeviceListManager.UserDevicesUpdateListener {
 
-    private var olmUtility: OlmUtility? = null
-
-    private var masterPkSigning: OlmPkSigning? = null
-    private var userPkSigning: OlmPkSigning? = null
-    private var selfSigningPkSigning: OlmPkSigning? = null
-
     init {
         try {
-            olmUtility = OlmUtility()
 
             // Try to get stored keys if they exist
             cryptoStore.getMyCrossSigningInfo()?.let { mxCrossSigningInfo ->
@@ -97,7 +90,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                                    masterPkSigning = pkSigning
+                                    crossSigningOlm.masterPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading master key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public master key does not match the private key")
@@ -110,7 +103,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                                    userPkSigning = pkSigning
+                                    crossSigningOlm.userPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading User Signing key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public User key does not match the private key")
@@ -123,7 +116,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                             ?.let { privateKeySeed ->
                                 val pkSigning = OlmPkSigning()
                                 if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                                    selfSigningPkSigning = pkSigning
+                                    crossSigningOlm.selfSigningPkSigning = pkSigning
                                     Timber.i("## CrossSigning - Loading Self Signing key success")
                                 } else {
                                     Timber.w("## CrossSigning - Public Self Signing key does not match the private key")
@@ -145,8 +138,7 @@ internal class DefaultCrossSigningService @Inject constructor(
     }
 
     fun release() {
-        olmUtility?.releaseUtility()
-        listOf(masterPkSigning, userPkSigning, selfSigningPkSigning).forEach { it?.releaseSigning() }
+        crossSigningOlm.release()
         deviceListManager.removeListener(this)
     }
 
@@ -179,9 +171,9 @@ internal class DefaultCrossSigningService @Inject constructor(
                     cryptoStore.setMyCrossSigningInfo(crossSigningInfo)
                     setUserKeysAsTrusted(userId, true)
                     cryptoStore.storePrivateKeysInfo(data.masterKeyPK, data.userKeyPK, data.selfSigningKeyPK)
-                    masterPkSigning = OlmPkSigning().apply { initWithSeed(data.masterKeyPK.fromBase64()) }
-                    userPkSigning = OlmPkSigning().apply { initWithSeed(data.userKeyPK.fromBase64()) }
-                    selfSigningPkSigning = OlmPkSigning().apply { initWithSeed(data.selfSigningKeyPK.fromBase64()) }
+                    crossSigningOlm.masterPkSigning = OlmPkSigning().apply { initWithSeed(data.masterKeyPK.fromBase64()) }
+                    crossSigningOlm.userPkSigning = OlmPkSigning().apply { initWithSeed(data.userKeyPK.fromBase64()) }
+                    crossSigningOlm.selfSigningPkSigning = OlmPkSigning().apply { initWithSeed(data.selfSigningKeyPK.fromBase64()) }
 
                     callback.onSuccess(Unit)
                 }
@@ -200,8 +192,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
+                            crossSigningOlm.masterPkSigning?.releaseSigning()
+                            crossSigningOlm.masterPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading MSK success")
                             cryptoStore.storeMSKPrivateKey(mskPrivateKey)
                             return
@@ -227,8 +219,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
+                            crossSigningOlm.selfSigningPkSigning?.releaseSigning()
+                            crossSigningOlm.selfSigningPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading SSK success")
                             cryptoStore.storeSSKPrivateKey(sskPrivateKey)
                             return
@@ -254,8 +246,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
+                            crossSigningOlm.userPkSigning?.releaseSigning()
+                            crossSigningOlm.userPkSigning = pkSigning
                             Timber.i("## CrossSigning - Loading USK success")
                             cryptoStore.storeUSKPrivateKey(uskPrivateKey)
                             return
@@ -284,8 +276,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.masterKey()?.unpaddedBase64PublicKey) {
-                            masterPkSigning?.releaseSigning()
-                            masterPkSigning = pkSigning
+                            crossSigningOlm.masterPkSigning?.releaseSigning()
+                            crossSigningOlm.masterPkSigning = pkSigning
                             masterKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -301,8 +293,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.userKey()?.unpaddedBase64PublicKey) {
-                            userPkSigning?.releaseSigning()
-                            userPkSigning = pkSigning
+                            crossSigningOlm.userPkSigning?.releaseSigning()
+                            crossSigningOlm.userPkSigning = pkSigning
                             userKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -318,8 +310,8 @@ internal class DefaultCrossSigningService @Inject constructor(
                     val pkSigning = OlmPkSigning()
                     try {
                         if (pkSigning.initWithSeed(privateKeySeed) == mxCrossSigningInfo.selfSigningKey()?.unpaddedBase64PublicKey) {
-                            selfSigningPkSigning?.releaseSigning()
-                            selfSigningPkSigning = pkSigning
+                            crossSigningOlm.selfSigningPkSigning?.releaseSigning()
+                            crossSigningOlm.selfSigningPkSigning = pkSigning
                             selfSignedKeyIsTrusted = true
                             Timber.i("## CrossSigning - Loading master key success")
                         } else {
@@ -407,7 +399,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Bob MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(masterKeySignaturesMadeByMyUserKey, myUserKey.unpaddedBase64PublicKey, otherMasterKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    masterKeySignaturesMadeByMyUserKey,
+                    myUserKey.unpaddedBase64PublicKey,
+                    otherMasterKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(myUserKey, masterKeySignaturesMadeByMyUserKey)
         }
@@ -461,7 +457,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                 if (potentialDevice != null && potentialDevice.isVerified) {
                     // Check signature validity?
                     try {
-                        olmUtility?.verifyEd25519Signature(value, potentialDevice.fingerprint(), myMasterKey.canonicalSignable())
+                        crossSigningOlm.olmUtility.verifyEd25519Signature(value, potentialDevice.fingerprint(), myMasterKey.canonicalSignable())
                         isMaterKeyTrusted = true
                         return@forEach
                     } catch (failure: Throwable) {
@@ -490,7 +486,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Alice MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(userKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, myUserKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    userKeySignaturesMadeByMyMasterKey,
+                    myMasterKey.unpaddedBase64PublicKey,
+                    myUserKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(myUserKey, userKeySignaturesMadeByMyMasterKey)
         }
@@ -509,7 +509,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check that Alice USK signature of Alice MSK is valid
         try {
-            olmUtility!!.verifyEd25519Signature(ssKeySignaturesMadeByMyMasterKey, myMasterKey.unpaddedBase64PublicKey, mySSKey.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    ssKeySignaturesMadeByMyMasterKey,
+                    myMasterKey.unpaddedBase64PublicKey,
+                    mySSKey.canonicalSignable()
+            )
         } catch (failure: Throwable) {
             return UserTrustResult.InvalidSignature(mySSKey, ssKeySignaturesMadeByMyMasterKey)
         }
@@ -562,7 +566,7 @@ internal class DefaultCrossSigningService @Inject constructor(
                 return@launch
             }
             val userPubKey = myKeys.userKey()?.unpaddedBase64PublicKey
-            if (userPubKey == null || userPkSigning == null) {
+            if (userPubKey == null || crossSigningOlm.userPkSigning == null) {
                 callback.onFailure(Throwable("## CrossSigning - Cannot sign from this account, privateKeyUnknown $userPubKey"))
                 return@launch
             }
@@ -571,7 +575,7 @@ internal class DefaultCrossSigningService @Inject constructor(
             val newSignature = JsonCanonicalizer.getCanonicalJson(
                     Map::class.java,
                     otherMasterKeys.signalableJSONDictionary()
-            ).let { userPkSigning?.sign(it) }
+            ).let { crossSigningOlm.userPkSigning?.sign(it) }
 
             if (newSignature == null) {
                 // race??
@@ -618,13 +622,13 @@ internal class DefaultCrossSigningService @Inject constructor(
             }
 
             val ssPubKey = myKeys.selfSigningKey()?.unpaddedBase64PublicKey
-            if (ssPubKey == null || selfSigningPkSigning == null) {
+            if (ssPubKey == null || crossSigningOlm.selfSigningPkSigning == null) {
                 callback.onFailure(Throwable("Cannot sign from this account, public and/or privateKey Unknown $ssPubKey"))
                 return@launch
             }
 
             // Sign with self signing
-            val newSignature = selfSigningPkSigning?.sign(device.canonicalSignable())
+            val newSignature = crossSigningOlm.selfSigningPkSigning?.sign(device.canonicalSignable())
 
             if (newSignature == null) {
                 // race??
@@ -697,7 +701,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check  bob's device is signed by bob's SSK
         try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    otherSSKSignature,
+                    otherKeys.selfSigningKey()?.unpaddedBase64PublicKey,
+                    otherDevice.canonicalSignable()
+            )
         } catch (e: Throwable) {
             return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDeviceId, otherSSKSignature, e))
         }
@@ -747,7 +755,11 @@ internal class DefaultCrossSigningService @Inject constructor(
 
         // Check  bob's device is signed by bob's SSK
         try {
-            olmUtility!!.verifyEd25519Signature(otherSSKSignature, otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, otherDevice.canonicalSignable())
+            crossSigningOlm.olmUtility.verifyEd25519Signature(
+                    otherSSKSignature,
+                    otherKeys.selfSigningKey()?.unpaddedBase64PublicKey,
+                    otherDevice.canonicalSignable()
+            )
         } catch (e: Throwable) {
             return legacyFallbackTrust(locallyTrusted, DeviceTrustResult.InvalidDeviceSignature(otherDevice.deviceId, otherSSKSignature, e))
         }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
index d2dae1c112..90c48fa4f7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/keysbackup/DefaultKeysBackupService.kt
@@ -54,6 +54,7 @@ import org.matrix.android.sdk.internal.crypto.MXOlmDevice
 import org.matrix.android.sdk.internal.crypto.MegolmSessionData
 import org.matrix.android.sdk.internal.crypto.ObjectSigner
 import org.matrix.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
+import org.matrix.android.sdk.internal.crypto.crosssigning.CrossSigningOlm
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.BackupKeysResult
 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.CreateKeysBackupVersionBody
@@ -102,6 +103,7 @@ internal class DefaultKeysBackupService @Inject constructor(
         private val cryptoStore: IMXCryptoStore,
         private val olmDevice: MXOlmDevice,
         private val objectSigner: ObjectSigner,
+        private val crossSigningOlm: CrossSigningOlm,
         // Actions
         private val megolmSessionDataImporter: MegolmSessionDataImporter,
         // Tasks
@@ -178,7 +180,6 @@ internal class DefaultKeysBackupService @Inject constructor(
                             }
                         }
                     }
-
                     val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
                     SignalableMegolmBackupAuthData(
                             publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
@@ -187,7 +188,6 @@ internal class DefaultKeysBackupService @Inject constructor(
                     )
                 } else {
                     val publicKey = olmPkDecryption.generateKey()
-
                     SignalableMegolmBackupAuthData(
                             publicKey = publicKey
                     )
@@ -195,13 +195,28 @@ internal class DefaultKeysBackupService @Inject constructor(
 
                 val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
 
+                val signatures = mutableMapOf<String, MutableMap<String, String>>()
+
+                val deviceSignature = objectSigner.signObject(canonicalJson)
+                deviceSignature.forEach { (userID, content) ->
+                    signatures[userID] = content.toMutableMap()
+                }
+
+                // If we have cross signing add signature, will throw if cross signing not properly configured
+                try {
+                    val crossSign = crossSigningOlm.signObject(CrossSigningOlm.KeyType.MASTER, canonicalJson)
+                    signatures[credentials.userId]?.putAll(crossSign)
+                } catch (failure: Throwable) {
+                    // ignore and log
+                    Timber.w(failure, "prepareKeysBackupVersion: failed to sign with cross signing keys")
+                }
+
                 val signedMegolmBackupAuthData = MegolmBackupAuthData(
                         publicKey = signalableMegolmBackupAuthData.publicKey,
                         privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
                         privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
-                        signatures = objectSigner.signObject(canonicalJson)
+                        signatures = signatures
                 )
-
                 val creationInfo = MegolmBackupCreationInfo(
                         algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
                         authData = signedMegolmBackupAuthData,
@@ -420,18 +435,41 @@ internal class DefaultKeysBackupService @Inject constructor(
 
         for ((keyId, mySignature) in mySigs) {
             // XXX: is this how we're supposed to get the device id?
-            var deviceId: String? = null
+            var deviceOrCrossSigningKeyId: String? = null
             val components = keyId.split(":")
             if (components.size == 2) {
-                deviceId = components[1]
+                deviceOrCrossSigningKeyId = components[1]
             }
 
-            if (deviceId != null) {
-                val device = cryptoStore.getUserDevice(userId, deviceId)
+            // Let's check if it's my master key
+            val myMSKPKey = cryptoStore.getMyCrossSigningInfo()?.masterKey()?.unpaddedBase64PublicKey
+            if (deviceOrCrossSigningKeyId == myMSKPKey) {
+                // we have to check if we can trust
+
+                var isSignatureValid = false
+                try {
+                    crossSigningOlm.verifySignature(CrossSigningOlm.KeyType.MASTER, authData.signalableJSONDictionary(), authData.signatures)
+                    isSignatureValid = true
+                } catch (failure: Throwable) {
+                    Timber.w(failure, "getKeysBackupTrust: Bad signature from my user MSK")
+                }
+                val mskTrusted = cryptoStore.getMyCrossSigningInfo()?.masterKey()?.trustLevel?.isVerified() == true
+                if (isSignatureValid && mskTrusted) {
+                    keysBackupVersionTrustIsUsable = true
+                }
+                val signature = KeysBackupVersionTrustSignature.UserSignature(
+                        keyId = deviceOrCrossSigningKeyId,
+                        cryptoCrossSigningKey = cryptoStore.getMyCrossSigningInfo()?.masterKey(),
+                        valid = isSignatureValid
+                )
+
+                keysBackupVersionTrustSignatures.add(signature)
+            } else if (deviceOrCrossSigningKeyId != null) {
+                val device = cryptoStore.getUserDevice(userId, deviceOrCrossSigningKeyId)
                 var isSignatureValid = false
 
                 if (device == null) {
-                    Timber.v("getKeysBackupTrust: Signature from unknown device $deviceId")
+                    Timber.v("getKeysBackupTrust: Signature from unknown device $deviceOrCrossSigningKeyId")
                 } else {
                     val fingerprint = device.fingerprint()
                     if (fingerprint != null) {
@@ -448,8 +486,8 @@ internal class DefaultKeysBackupService @Inject constructor(
                     }
                 }
 
-                val signature = KeysBackupVersionTrustSignature(
-                        deviceId = deviceId,
+                val signature = KeysBackupVersionTrustSignature.DeviceSignature(
+                        deviceId = deviceOrCrossSigningKeyId,
                         device = device,
                         valid = isSignatureValid,
                 )
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
index a4f6587be4..a32cd7caa7 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt
@@ -128,7 +128,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
     }
 
     private fun launch4SActivity() {
-        SharedSecureStorageActivity.newIntent(
+        SharedSecureStorageActivity.newReadIntent(
                 context = this,
                 keyId = null, // default key
                 requestedSecrets = listOf(KEYBACKUP_SECRET_SSSS_NAME),
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeyBackupSettingsAction.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeyBackupSettingsAction.kt
index 776c7bb521..0d19ae630b 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeyBackupSettingsAction.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeyBackupSettingsAction.kt
@@ -22,4 +22,8 @@ sealed class KeyBackupSettingsAction : VectorViewModelAction {
     object Init : KeyBackupSettingsAction()
     object GetKeyBackupTrust : KeyBackupSettingsAction()
     object DeleteKeyBackup : KeyBackupSettingsAction()
+    object SetUpKeyBackup : KeyBackupSettingsAction()
+    data class StoreIn4SSuccess(val recoveryKey: String, val alias: String) : KeyBackupSettingsAction()
+    object StoreIn4SReset : KeyBackupSettingsAction()
+    object StoreIn4SFailure : KeyBackupSettingsAction()
 }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
index 13df109dd5..6893e8e76f 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt
@@ -15,6 +15,7 @@
  */
 package im.vector.app.features.crypto.keysbackup.settings
 
+import android.app.Activity
 import android.content.Context
 import android.content.Intent
 import com.airbnb.mvrx.Fail
@@ -23,9 +24,13 @@ import com.airbnb.mvrx.viewModel
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import dagger.hilt.android.AndroidEntryPoint
 import im.vector.app.R
+import im.vector.app.core.extensions.registerStartForActivityResult
 import im.vector.app.core.extensions.replaceFragment
 import im.vector.app.core.platform.SimpleFragmentActivity
 import im.vector.app.core.platform.WaitingViewData
+import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
+import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
+import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
 
 @AndroidEntryPoint
 class KeysBackupManageActivity : SimpleFragmentActivity() {
@@ -41,6 +46,21 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
 
     private val viewModel: KeysBackupSettingsViewModel by viewModel()
 
+    private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
+        if (activityResult.resultCode == Activity.RESULT_OK) {
+            val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
+            val reset = activityResult.data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
+            if (result != null) {
+                viewModel.handle(KeyBackupSettingsAction.StoreIn4SSuccess(result, SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS))
+            } else if (reset) {
+                // all have been reset so a new backup would have been created
+                viewModel.handle(KeyBackupSettingsAction.StoreIn4SReset)
+            }
+        } else {
+            viewModel.handle(KeyBackupSettingsAction.StoreIn4SFailure)
+        }
+    }
+
     override fun initUiAndData() {
         super.initUiAndData()
         if (supportFragmentManager.fragments.isEmpty()) {
@@ -69,6 +89,23 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
                 }
             }
         }
+
+        viewModel.observeViewEvents {
+            when (it) {
+                KeysBackupViewEvents.OpenLegacyCreateBackup  -> {
+                    startActivity(KeysBackupSetupActivity.intent(this, false))
+                }
+                is KeysBackupViewEvents.RequestStore4SSecret -> {
+                    secretStartForActivityResult.launch(
+                            SharedSecureStorageActivity.newWriteIntent(
+                                    this,
+                                    null, // default key
+                                    listOf(KEYBACKUP_SECRET_SSSS_NAME to it.recoveryKey)
+                            )
+                    )
+                }
+            }
+        }
     }
 
     override fun onBackPressed() {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
index 4d3ec9a820..edc44fa796 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt
@@ -28,7 +28,6 @@ import im.vector.app.core.extensions.configureWith
 import im.vector.app.core.platform.VectorBaseFragment
 import im.vector.app.databinding.FragmentKeysBackupSettingsBinding
 import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
-import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity
 import javax.inject.Inject
 
 class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController) :
@@ -58,9 +57,7 @@ class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSetti
     }
 
     override fun didSelectSetupMessageRecovery() {
-        context?.let {
-            startActivity(KeysBackupSetupActivity.intent(it, false))
-        }
+        viewModel.handle(KeyBackupSettingsAction.SetUpKeyBackup)
     }
 
     override fun didSelectRestoreMessageRecovery() {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt
index d281360678..d13b97a9ba 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsRecyclerViewController.kt
@@ -29,9 +29,11 @@ import im.vector.app.core.ui.list.ItemStyle
 import im.vector.app.core.ui.list.genericItem
 import im.vector.app.features.settings.VectorPreferences
 import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
+import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrustSignature
 import java.util.UUID
 import javax.inject.Inject
 
@@ -191,69 +193,105 @@ class KeysBackupSettingsRecyclerViewController @Inject constructor(
                 }
             }
             is Success       -> {
-                keysVersionTrust().signatures.forEach {
-                    genericItem {
-                        id(UUID.randomUUID().toString())
-                        title(host.stringProvider.getString(R.string.keys_backup_info_title_signature).toEpoxyCharSequence())
-
-                        val isDeviceKnown = it.device != null
-                        val isDeviceVerified = it.device?.isVerified ?: false
-                        val isSignatureValid = it.valid
-                        val deviceId: String = it.deviceId ?: ""
-
-                        if (!isDeviceKnown) {
-                            description(
-                                    host.stringProvider
-                                            .getString(R.string.keys_backup_settings_signature_from_unknown_device, deviceId)
-                                            .toEpoxyCharSequence()
-                            )
-                            endIconResourceId(R.drawable.e2e_warning)
-                        } else {
-                            if (isSignatureValid) {
-                                if (host.session.sessionParams.deviceId == it.deviceId) {
+                keysVersionTrust()
+                        .signatures
+                        .filterIsInstance<KeysBackupVersionTrustSignature.UserSignature>()
+                        .forEach {
+                            val isUserVerified = it.cryptoCrossSigningKey?.trustLevel?.isVerified().orFalse()
+                            val isSignatureValid = it.valid
+                            val userId: String = it.cryptoCrossSigningKey?.userId ?: ""
+                            if (userId == session.sessionParams.userId && isSignatureValid && isUserVerified) {
+                                genericItem {
+                                    id(UUID.randomUUID().toString())
+                                    title(host.stringProvider.getString(R.string.keys_backup_info_title_signature).toEpoxyCharSequence())
                                     description(
                                             host.stringProvider
-                                                    .getString(R.string.keys_backup_settings_valid_signature_from_this_device)
+                                                    .getString(R.string.keys_backup_settings_signature_from_this_user)
                                                     .toEpoxyCharSequence()
                                     )
                                     endIconResourceId(R.drawable.e2e_verified)
-                                } else {
-                                    if (isDeviceVerified) {
-                                        description(
-                                                host.stringProvider
-                                                        .getString(R.string.keys_backup_settings_valid_signature_from_verified_device, deviceId)
-                                                        .toEpoxyCharSequence()
-                                        )
-                                        endIconResourceId(R.drawable.e2e_verified)
-                                    } else {
-                                        description(
-                                                host.stringProvider
-                                                        .getString(R.string.keys_backup_settings_valid_signature_from_unverified_device, deviceId)
-                                                        .toEpoxyCharSequence()
-                                        )
-                                        endIconResourceId(R.drawable.e2e_warning)
-                                    }
-                                }
-                            } else {
-                                // Invalid signature
-                                endIconResourceId(R.drawable.e2e_warning)
-                                if (isDeviceVerified) {
-                                    description(
-                                            host.stringProvider
-                                                    .getString(R.string.keys_backup_settings_invalid_signature_from_verified_device, deviceId)
-                                                    .toEpoxyCharSequence()
-                                    )
-                                } else {
-                                    description(
-                                            host.stringProvider
-                                                    .getString(R.string.keys_backup_settings_invalid_signature_from_unverified_device, deviceId)
-                                                    .toEpoxyCharSequence()
-                                    )
                                 }
                             }
                         }
-                    }
-                } // end for each
+
+                keysVersionTrust()
+                        .signatures
+                        .filterIsInstance<KeysBackupVersionTrustSignature.DeviceSignature>()
+                        .forEach {
+                            genericItem {
+                                id(UUID.randomUUID().toString())
+                                title(host.stringProvider.getString(R.string.keys_backup_info_title_signature).toEpoxyCharSequence())
+
+                                val isDeviceKnown = it.device != null
+                                val isDeviceVerified = it.device?.isVerified ?: false
+                                val isSignatureValid = it.valid
+                                val deviceId: String = it.deviceId ?: ""
+
+                                if (!isDeviceKnown) {
+                                    description(
+                                            host.stringProvider
+                                                    .getString(R.string.keys_backup_settings_signature_from_unknown_device, deviceId)
+                                                    .toEpoxyCharSequence()
+                                    )
+                                    endIconResourceId(R.drawable.e2e_warning)
+                                } else {
+                                    if (isSignatureValid) {
+                                        if (host.session.sessionParams.deviceId == it.deviceId) {
+                                            description(
+                                                    host.stringProvider
+                                                            .getString(R.string.keys_backup_settings_valid_signature_from_this_device)
+                                                            .toEpoxyCharSequence()
+                                            )
+                                            endIconResourceId(R.drawable.e2e_verified)
+                                        } else {
+                                            if (isDeviceVerified) {
+                                                description(
+                                                        host.stringProvider
+                                                                .getString(
+                                                                        R.string.keys_backup_settings_valid_signature_from_verified_device,
+                                                                        deviceId
+                                                                )
+                                                                .toEpoxyCharSequence()
+                                                )
+                                                endIconResourceId(R.drawable.e2e_verified)
+                                            } else {
+                                                description(
+                                                        host.stringProvider
+                                                                .getString(
+                                                                        R.string.keys_backup_settings_valid_signature_from_unverified_device,
+                                                                        deviceId
+                                                                )
+                                                                .toEpoxyCharSequence()
+                                                )
+                                                endIconResourceId(R.drawable.e2e_warning)
+                                            }
+                                        }
+                                    } else {
+                                        // Invalid signature
+                                        endIconResourceId(R.drawable.e2e_warning)
+                                        if (isDeviceVerified) {
+                                            description(
+                                                    host.stringProvider
+                                                            .getString(
+                                                                    R.string.keys_backup_settings_invalid_signature_from_verified_device,
+                                                                    deviceId
+                                                            )
+                                                            .toEpoxyCharSequence()
+                                            )
+                                        } else {
+                                            description(
+                                                    host.stringProvider
+                                                            .getString(
+                                                                    R.string.keys_backup_settings_invalid_signature_from_unverified_device,
+                                                                    deviceId
+                                                            )
+                                                            .toEpoxyCharSequence()
+                                            )
+                                        }
+                                    }
+                                }
+                            }
+                        } // end for each
             }
             is Fail          -> {
                 errorWithRetryItem {
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
index ca6edf0941..3a76b5cdd8 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupSettingsViewModel.kt
@@ -25,8 +25,8 @@ import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import im.vector.app.core.di.MavericksAssistedViewModelFactory
 import im.vector.app.core.di.hiltMavericksViewModelFactory
-import im.vector.app.core.platform.EmptyViewEvents
 import im.vector.app.core.platform.VectorViewModel
+import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.MatrixCallback
 import org.matrix.android.sdk.api.NoOpMatrixCallback
 import org.matrix.android.sdk.api.session.Session
@@ -34,10 +34,16 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
 import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
+import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
+import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
+import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
+import org.matrix.android.sdk.api.util.awaitCallback
+import org.matrix.android.sdk.api.util.toBase64NoPadding
+import timber.log.Timber
 
 class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialState: KeysBackupSettingViewState,
-                                                              session: Session
-) : VectorViewModel<KeysBackupSettingViewState, KeyBackupSettingsAction, EmptyViewEvents>(initialState),
+                                                              private val session: Session
+) : VectorViewModel<KeysBackupSettingViewState, KeyBackupSettingsAction, KeysBackupViewEvents>(initialState),
         KeysBackupStateListener {
 
     @AssistedFactory
@@ -49,6 +55,8 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
 
     private val keysBackupService: KeysBackupService = session.cryptoService().keysBackupService()
 
+    var pendingBackupCreationInfo: MegolmBackupCreationInfo? = null
+
     init {
         setState {
             this.copy(
@@ -62,9 +70,18 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
 
     override fun handle(action: KeyBackupSettingsAction) {
         when (action) {
-            KeyBackupSettingsAction.Init              -> init()
-            KeyBackupSettingsAction.GetKeyBackupTrust -> getKeysBackupTrust()
-            KeyBackupSettingsAction.DeleteKeyBackup   -> deleteCurrentBackup()
+            KeyBackupSettingsAction.Init                -> init()
+            KeyBackupSettingsAction.GetKeyBackupTrust   -> getKeysBackupTrust()
+            KeyBackupSettingsAction.DeleteKeyBackup     -> deleteCurrentBackup()
+            KeyBackupSettingsAction.SetUpKeyBackup      -> viewModelScope.launch {
+                setUpKeyBackup()
+            }
+            KeyBackupSettingsAction.StoreIn4SReset,
+            KeyBackupSettingsAction.StoreIn4SFailure    -> {
+                pendingBackupCreationInfo = null
+                // nothing to do just stay on fragment
+            }
+            is KeyBackupSettingsAction.StoreIn4SSuccess -> viewModelScope.launch { completeBackupCreation() }
         }
     }
 
@@ -120,6 +137,35 @@ class KeysBackupSettingsViewModel @AssistedInject constructor(@Assisted initialS
         getKeysBackupTrust()
     }
 
+    suspend fun setUpKeyBackup() {
+        // We need to check if 4S is enabled first.
+        // If it is we need to use it, generate a random key
+        // for the backup and store it in the 4S
+        if (session.sharedSecretStorageService().isRecoverySetup()) {
+            val creationInfo = awaitCallback<MegolmBackupCreationInfo> {
+                session.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, it)
+            }
+            pendingBackupCreationInfo = creationInfo
+            val recoveryKey = extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey)?.toBase64NoPadding()
+            _viewEvents.post(KeysBackupViewEvents.RequestStore4SSecret(recoveryKey!!))
+        } else {
+            // No 4S so we can open legacy flow
+            _viewEvents.post(KeysBackupViewEvents.OpenLegacyCreateBackup)
+        }
+    }
+
+    suspend fun completeBackupCreation() {
+        val info = pendingBackupCreationInfo ?: return
+        val version = awaitCallback<KeysVersion> {
+            session.cryptoService().keysBackupService().createKeysBackupVersion(info, it)
+        }
+        // Save it for gossiping
+        Timber.d("## BootstrapCrossSigningTask: Creating 4S - Save megolm backup key for gossiping")
+        session.cryptoService().keysBackupService().saveBackupRecoveryKey(info.recoveryKey, version = version.version)
+
+        // TODO catch, delete 4S account data
+    }
+
     private fun deleteCurrentBackup() {
         val keysBackupService = keysBackupService
 
diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupViewEvents.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupViewEvents.kt
new file mode 100644
index 0000000000..b39a516772
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/settings/KeysBackupViewEvents.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 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.app.features.crypto.keysbackup.settings
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed class KeysBackupViewEvents : VectorViewEvents {
+    object OpenLegacyCreateBackup : KeysBackupViewEvents()
+    data class RequestStore4SSecret(val recoveryKey: String) : KeysBackupViewEvents()
+}
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
index 8ca1dec6d7..40ad2859fe 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageActivity.kt
@@ -48,8 +48,9 @@ class SharedSecureStorageActivity :
     @Parcelize
     data class Args(
             val keyId: String?,
-            val requestedSecrets: List<String>,
-            val resultKeyStoreAlias: String
+            val requestedSecrets: List<String> = emptyList(),
+            val resultKeyStoreAlias: String,
+            val writeSecrets: List<Pair<String, String>> = emptyList(),
     ) : Parcelable
 
     private val viewModel: SharedSecureStorageViewModel by viewModel()
@@ -148,18 +149,36 @@ class SharedSecureStorageActivity :
         const val EXTRA_DATA_RESET = "EXTRA_DATA_RESET"
         const val DEFAULT_RESULT_KEYSTORE_ALIAS = "SharedSecureStorageActivity"
 
-        fun newIntent(context: Context,
-                      keyId: String? = null,
-                      requestedSecrets: List<String>,
-                      resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent {
+        fun newReadIntent(context: Context,
+                          keyId: String? = null,
+                          requestedSecrets: List<String>,
+                          resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent {
             require(requestedSecrets.isNotEmpty())
             return Intent(context, SharedSecureStorageActivity::class.java).also {
                 it.putExtra(
-                        Mavericks.KEY_ARG, Args(
-                        keyId,
-                        requestedSecrets,
-                        resultKeyStoreAlias
+                        Mavericks.KEY_ARG,
+                        Args(
+                                keyId = keyId,
+                                requestedSecrets = requestedSecrets,
+                                resultKeyStoreAlias = resultKeyStoreAlias
+                        )
                 )
+            }
+        }
+
+        fun newWriteIntent(context: Context,
+                           keyId: String? = null,
+                           writeSecrets: List<Pair<String, String>>,
+                           resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent {
+            require(writeSecrets.isNotEmpty())
+            return Intent(context, SharedSecureStorageActivity::class.java).also {
+                it.putExtra(
+                        Mavericks.KEY_ARG,
+                        Args(
+                                keyId = keyId,
+                                writeSecrets = writeSecrets,
+                                resultKeyStoreAlias = resultKeyStoreAlias
+                        )
                 )
             }
         }
diff --git a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
index 3fafda54a3..e045ac020d 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/quads/SharedSecureStorageViewModel.kt
@@ -39,13 +39,20 @@ import kotlinx.coroutines.withContext
 import org.matrix.android.sdk.api.listeners.ProgressListener
 import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
+import org.matrix.android.sdk.api.session.securestorage.KeyInfo
 import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
 import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec
+import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService
 import org.matrix.android.sdk.api.util.toBase64NoPadding
 import org.matrix.android.sdk.flow.flow
 import timber.log.Timber
 import java.io.ByteArrayOutputStream
 
+sealed class RequestType {
+    data class ReadSecrets(val secretsName: List<String>) : RequestType()
+    data class WriteSecrets(val secretsNameValue: List<Pair<String, String>>) : RequestType()
+}
+
 data class SharedSecureStorageViewState(
         val ready: Boolean = false,
         val hasPassphrase: Boolean = true,
@@ -55,13 +62,17 @@ data class SharedSecureStorageViewState(
         val showResetAllAction: Boolean = false,
         val userId: String = "",
         val keyId: String?,
-        val requestedSecrets: List<String>,
+        val requestType: RequestType,
         val resultKeyStoreAlias: String
 ) : MavericksState {
 
     constructor(args: SharedSecureStorageActivity.Args) : this(
             keyId = args.keyId,
-            requestedSecrets = args.requestedSecrets,
+            requestType = if (args.writeSecrets.isNotEmpty()) {
+                RequestType.WriteSecrets(args.writeSecrets)
+            } else {
+                RequestType.ReadSecrets(args.requestedSecrets)
+            },
             resultKeyStoreAlias = args.resultKeyStoreAlias
     )
 
@@ -87,14 +98,17 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
         setState {
             copy(userId = session.myUserId)
         }
-        val integrityResult = session.sharedSecretStorageService().checkShouldBeAbleToAccessSecrets(initialState.requestedSecrets, initialState.keyId)
-        if (integrityResult !is IntegrityResult.Success) {
-            _viewEvents.post(
-                    SharedSecureStorageViewEvent.Error(
-                            stringProvider.getString(R.string.enter_secret_storage_invalid),
-                            true
-                    )
-            )
+        if (initialState.requestType is RequestType.ReadSecrets) {
+            val integrityResult =
+                    session.sharedSecretStorageService().checkShouldBeAbleToAccessSecrets(initialState.requestType.secretsName, initialState.keyId)
+            if (integrityResult !is IntegrityResult.Success) {
+                _viewEvents.post(
+                        SharedSecureStorageViewEvent.Error(
+                                stringProvider.getString(R.string.enter_secret_storage_invalid),
+                                true
+                        )
+                )
+            }
         }
         val keyResult = initialState.keyId?.let { session.sharedSecretStorageService().getKey(it) }
                 ?: session.sharedSecretStorageService().getDefaultKey()
@@ -226,20 +240,8 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                     _viewEvents.post(SharedSecureStorageViewEvent.HideModalLoading)
                     setState { copy(checkingSSSSAction = Fail(IllegalArgumentException(stringProvider.getString(R.string.bootstrap_invalid_recovery_key)))) }
                 }
-
                 withContext(Dispatchers.IO) {
-                    initialState.requestedSecrets.forEach {
-                        if (session.accountDataService().getUserAccountDataEvent(it) != null) {
-                            val res = session.sharedSecretStorageService().getSecret(
-                                    name = it,
-                                    keyId = keyInfo.id,
-                                    secretKey = keySpec
-                            )
-                            decryptedSecretMap[it] = res
-                        } else {
-                            Timber.w("## Cannot find secret $it in SSSS, skip")
-                        }
-                    }
+                    performRequest(keyInfo, keySpec, decryptedSecretMap)
                 }
             }.fold({
                 setState { copy(checkingSSSSAction = Success(Unit)) }
@@ -258,6 +260,37 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
         }
     }
 
+    private suspend fun performRequest(keyInfo: KeyInfo, keySpec: RawBytesKeySpec, decryptedSecretMap: HashMap<String, String>) {
+        when (val requestType = initialState.requestType) {
+            is RequestType.ReadSecrets  -> {
+                requestType.secretsName.forEach {
+                    if (session.accountDataService().getUserAccountDataEvent(it) != null) {
+                        val res = session.sharedSecretStorageService().getSecret(
+                                name = it,
+                                keyId = keyInfo.id,
+                                secretKey = keySpec
+                        )
+                        decryptedSecretMap[it] = res
+                    } else {
+                        Timber.w("## Cannot find secret $it in SSSS, skip")
+                    }
+                }
+            }
+            is RequestType.WriteSecrets -> {
+                requestType.secretsNameValue.forEach {
+                    val (name, value) = it
+
+                    session.sharedSecretStorageService().storeSecret(
+                            name = name,
+                            secretBase64 = value,
+                            keys = listOf(SharedSecretStorageService.KeyRef(keyInfo.id, keySpec))
+                    )
+                    decryptedSecretMap[name] = value
+                }
+            }
+        }
+    }
+
     private fun handleSubmitPassphrase(action: SharedSecureStorageAction.SubmitPassphrase) {
         _viewEvents.post(SharedSecureStorageViewEvent.ShowModalLoading)
         val decryptedSecretMap = HashMap<String, String>()
@@ -302,17 +335,8 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
                 )
 
                 withContext(Dispatchers.IO) {
-                    initialState.requestedSecrets.forEach {
-                        if (session.accountDataService().getUserAccountDataEvent(it) != null) {
-                            val res = session.sharedSecretStorageService().getSecret(
-                                    name = it,
-                                    keyId = keyInfo.id,
-                                    secretKey = keySpec
-                            )
-                            decryptedSecretMap[it] = res
-                        } else {
-                            Timber.w("## Cannot find secret $it in SSSS, skip")
-                        }
+                    withContext(Dispatchers.IO) {
+                        performRequest(keyInfo, keySpec, decryptedSecretMap)
                     }
                 }
             }.fold({
diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
index 9c6c22b6ca..dc79136cad 100644
--- a/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
+++ b/vector/src/main/java/im/vector/app/features/crypto/verification/VerificationBottomSheet.kt
@@ -95,14 +95,12 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetV
             when (it) {
                 is VerificationBottomSheetViewEvents.Dismiss           -> dismiss()
                 is VerificationBottomSheetViewEvents.AccessSecretStore -> {
-                    secretStartForActivityResult.launch(
-                            SharedSecureStorageActivity.newIntent(
-                                    requireContext(),
-                                    null, // use default key
-                                    listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
-                                    SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
-                            )
-                    )
+                    secretStartForActivityResult.launch(SharedSecureStorageActivity.newReadIntent(
+                            requireContext(),
+                            null, // use default key
+                            listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
+                            SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
+                    ))
                 }
                 is VerificationBottomSheetViewEvents.ModalError        -> {
                     MaterialAlertDialogBuilder(requireContext())
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 1868d1ff5b..7a0bde96f0 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -1513,6 +1513,7 @@
     <string name="keys_backup_settings_status_not_setup">Your keys are not being backed up from this session.</string>
 
     <string name="keys_backup_settings_signature_from_unknown_device">Backup has a signature from unknown session with ID %s.</string>
+    <string name="keys_backup_settings_signature_from_this_user">Backup has a valid signature from this user.</string>
     <string name="keys_backup_settings_valid_signature_from_this_device">Backup has a valid signature from this session.</string>
     <string name="keys_backup_settings_valid_signature_from_verified_device">Backup has a valid signature from verified session %s.</string>
     <string name="keys_backup_settings_valid_signature_from_unverified_device">Backup has a valid signature from unverified session %s</string>