Use BackupRecoveryKey instead of plain string

This commit is contained in:
ganfra 2022-05-25 14:45:31 +02:00
parent 7c76ba8184
commit b0aae84727
16 changed files with 101 additions and 75 deletions

View file

@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_S
import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
@ -250,7 +251,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
return MegolmBackupCreationInfo(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
authData = createFakeMegolmBackupAuthData(),
recoveryKey = "fake"
recoveryKey = BackupRecoveryKey.fromBase58("3cnTdW")
)
}
@ -445,7 +446,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
// Save it for gossiping
session.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey)?.toBase64NoPadding()?.let { secret ->
extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey.toBase58())?.toBase64NoPadding()?.let { secret ->
ssssService.storeSecret(
KEYBACKUP_SECRET_SSSS_NAME,
secret,

View file

@ -34,6 +34,7 @@ import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
import org.matrix.android.sdk.api.listeners.StepProgressListener
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
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.toKeysVersionResult
@ -505,7 +506,7 @@ class KeysBackupTest : InstrumentedTest {
try {
testData.aliceSession2.cryptoService().keysBackupService().trustKeysBackupVersionWithRecoveryKey(
testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
"Bad recovery key"
BackupRecoveryKey.fromBase58("Bad recovery key")
)
fail("Should have failed to trust")
} catch (failure: Throwable) {
@ -645,7 +646,7 @@ class KeysBackupTest : InstrumentedTest {
var importRoomKeysResult: ImportRoomKeysResult? = null
testHelper.runBlockingTest {
testData.aliceSession2.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(testData.aliceSession2.cryptoService().keysBackupService().keysBackupVersion!!,
"EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d",
BackupRecoveryKey.fromBase58("EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d"),
null,
null,
null

View file

@ -142,8 +142,7 @@ interface KeysBackupService {
* @param keysBackupVersion the backup version to check.
* @param recoveryKey the recovery key to challenge with the key backup public key.
*/
suspend fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult,
recoveryKey: String)
suspend fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, recoveryKey: BackupRecoveryKey)
/**
* Set trust on a keys backup version.
@ -167,7 +166,7 @@ interface KeysBackupService {
* @param callback Callback. It provides the number of found keys and the number of successfully imported keys.
*/
suspend fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
recoveryKey: String, roomId: String?,
recoveryKey: BackupRecoveryKey, roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?): ImportRoomKeysResult
@ -194,10 +193,10 @@ interface KeysBackupService {
val state: KeysBackupState
// For gossiping
fun saveBackupRecoveryKey(recoveryKey: String?, version: String?)
fun saveBackupRecoveryKey(recoveryKey: BackupRecoveryKey?, version: String?)
suspend fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo?
suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String): Boolean
suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: BackupRecoveryKey): Boolean
fun computePrivateKey(passphrase: String,
privateKeySalt: String,

View file

@ -31,7 +31,7 @@ data class MegolmBackupCreationInfo(
val authData: MegolmBackupAuthData,
/**
* The Base58 recovery key.
* The recovery key.
*/
val recoveryKey: String
val recoveryKey: BackupRecoveryKey
)

View file

@ -17,6 +17,6 @@
package org.matrix.android.sdk.api.session.crypto.keysbackup
data class SavedKeyBackupKeyInfo(
val recoveryKey: String,
val recoveryKey: BackupRecoveryKey,
val version: String
)

View file

@ -20,10 +20,9 @@ import dagger.Lazy
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
import org.matrix.android.sdk.api.util.awaitCallback
import org.matrix.android.sdk.internal.crypto.keysbackup.RustKeyBackupService
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.util.time.Clock
@ -101,12 +100,12 @@ internal class PerSessionBackupQueryRateLimiter @Inject constructor(
(now - lastTry.timestamp) > MIN_TRY_BACKUP_PERIOD_MILLIS
if (!shouldQuery) return false
val recoveryKey = savedKeyBackupKeyInfo?.recoveryKey ?: return false
val successfullyImported = withContext(coroutineDispatchers.io) {
try {
keysBackupService.get().restoreKeysWithRecoveryKey(
currentVersion,
savedKeyBackupKeyInfo?.recoveryKey ?: "",
recoveryKey,
roomId,
sessionId,
null,

View file

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixError
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.listeners.StepProgressListener
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupLastVersionResult
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
@ -60,7 +61,6 @@ import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.olm.OlmException
import timber.log.Timber
import uniffi.olm.BackupRecoveryKey
import uniffi.olm.Request
import uniffi.olm.RequestType
import java.security.InvalidParameterException
@ -150,7 +150,7 @@ internal class RustKeyBackupService @Inject constructor(
MegolmBackupCreationInfo(
algorithm = publicKey.backupAlgorithm,
authData = signedMegolmBackupAuthData,
recoveryKey = key.toBase58()
recoveryKey = key
)
}
}
@ -189,9 +189,11 @@ internal class RustKeyBackupService @Inject constructor(
}
}
override fun saveBackupRecoveryKey(recoveryKey: String?, version: String?) {
override fun saveBackupRecoveryKey(recoveryKey: BackupRecoveryKey?, version: String?) {
cryptoCoroutineScope.launch {
olmMachine.saveRecoveryKey(recoveryKey, version)
val recoveryKeyStr = recoveryKey?.toBase64()
// TODO : change rust API to use BackupRecoveryKey
olmMachine.saveRecoveryKey(recoveryKeyStr, version)
}
}
@ -312,7 +314,8 @@ internal class RustKeyBackupService @Inject constructor(
val body = UpdateKeysBackupVersionBody(
algorithm = keysBackupVersion.algorithm,
authData = newAuthData.copy(signatures = newSignatures).toJsonDict(),
version = keysBackupVersion.version)
version = keysBackupVersion.version
)
withContext(coroutineDispatchers.io) {
sender.updateBackup(keysBackupVersion, body)
@ -353,14 +356,13 @@ internal class RustKeyBackupService @Inject constructor(
}
}
override suspend fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, recoveryKey: String) {
override suspend fun trustKeysBackupVersionWithRecoveryKey(keysBackupVersion: KeysVersionResult, recoveryKey: BackupRecoveryKey) {
Timber.v("trustKeysBackupVersionWithRecoveryKey: version ${keysBackupVersion.version}")
withContext(coroutineDispatchers.crypto) {
// This is ~nowhere mentioned, the string here is actually a base58 encoded key.
// This not really supported by the spec for the backup key, the 4S key supports
// base58 encoding and the same method seems to be used here.
val key = BackupRecoveryKey.fromBase58(recoveryKey)
checkRecoveryKey(key, keysBackupVersion)
checkRecoveryKey(recoveryKey, keysBackupVersion)
trustKeysBackupVersion(keysBackupVersion, true)
}
}
@ -378,7 +380,7 @@ internal class RustKeyBackupService @Inject constructor(
withContext(coroutineDispatchers.crypto) {
try {
val version = sender.getKeyBackupLastVersion()?.toKeysVersionResult()
Timber.v("Keybackup version: $version")
if (version != null) {
val key = BackupRecoveryKey.fromBase64(secret)
if (isValidRecoveryKey(key, version)) {
@ -395,7 +397,9 @@ internal class RustKeyBackupService @Inject constructor(
}
}
// we can save, it's valid
saveBackupRecoveryKey(key.toBase64(), version.version)
saveBackupRecoveryKey(key, version.version)
} else {
Timber.d("Invalid recovery key")
}
} else {
Timber.e("onSecretKeyGossip: Failed to import backup recovery key, no backup version was found on the server")
@ -480,7 +484,7 @@ internal class RustKeyBackupService @Inject constructor(
}
// Save for next time and for gossiping
saveBackupRecoveryKey(recoveryKey.toBase64(), keysVersionResult.version)
saveBackupRecoveryKey(recoveryKey, keysVersionResult.version)
}
withContext(coroutineDispatchers.main) {
@ -519,14 +523,18 @@ internal class RustKeyBackupService @Inject constructor(
stepProgressListener?.onStepProgress(stepProgress)
}
Timber.v("restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
" of ${data.roomIdToRoomKeysBackupData.size} rooms from the backup store on the homeserver")
Timber.v(
"restoreKeysWithRecoveryKey: Decrypted ${sessionsData.size} keys out" +
" of ${data.roomIdToRoomKeysBackupData.size} rooms from the backup store on the homeserver"
)
// Do not trigger a backup for them if they come from the backup version we are using
val backUp = keysVersionResult.version != keysBackupVersion?.version
if (backUp) {
Timber.v("restoreKeysWithRecoveryKey: Those keys will be backed up" +
" to backup version: ${keysBackupVersion?.version}")
Timber.v(
"restoreKeysWithRecoveryKey: Those keys will be backed up" +
" to backup version: ${keysBackupVersion?.version}"
)
}
// Import them into the crypto store
@ -557,15 +565,12 @@ internal class RustKeyBackupService @Inject constructor(
}
override suspend fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
recoveryKey: String,
recoveryKey: BackupRecoveryKey,
roomId: String?,
sessionId: String?,
stepProgressListener: StepProgressListener?): ImportRoomKeysResult {
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
val key = BackupRecoveryKey.fromBase58(recoveryKey)
return restoreBackup(keysVersionResult, key, roomId, sessionId, stepProgressListener)
return restoreBackup(keysVersionResult, recoveryKey, roomId, sessionId, stepProgressListener)
}
override suspend fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
@ -577,7 +582,6 @@ internal class RustKeyBackupService @Inject constructor(
val recoveryKey = withContext(coroutineDispatchers.crypto) {
recoveryKeyFromPassword(password, keysBackupVersion)
}
return restoreBackup(keysBackupVersion, recoveryKey, roomId, sessionId, stepProgressListener)
}
@ -703,16 +707,15 @@ internal class RustKeyBackupService @Inject constructor(
private fun isValidRecoveryKey(recoveryKey: BackupRecoveryKey, version: KeysVersionResult): Boolean {
val publicKey = recoveryKey.megolmV1PublicKey().publicKey
val authData = getMegolmBackupAuthData(version) ?: return false
Timber.v("recoveryKey.megolmV1PublicKey().publicKey $publicKey == getMegolmBackupAuthData(version).publicKey ${authData.publicKey}")
return authData.publicKey == publicKey
}
override suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: String): Boolean {
override suspend fun isValidRecoveryKeyForCurrentVersion(recoveryKey: BackupRecoveryKey): Boolean {
return withContext(coroutineDispatchers.crypto) {
val keysBackupVersion = keysBackupVersion ?: return@withContext false
val key = BackupRecoveryKey.fromBase64(recoveryKey)
try {
isValidRecoveryKey(key, keysBackupVersion)
isValidRecoveryKey(recoveryKey, keysBackupVersion)
} catch (failure: Throwable) {
Timber.i("isValidRecoveryKeyForCurrentVersion: Invalid recovery key")
false
@ -726,7 +729,9 @@ internal class RustKeyBackupService @Inject constructor(
override suspend fun getKeyBackupRecoveryKeyInfo(): SavedKeyBackupKeyInfo? {
val info = olmMachine.getBackupKeys() ?: return null
return SavedKeyBackupKeyInfo(info.recoveryKey, info.backupVersion)
// TODO change rust ffi to return BackupRecoveryKey instead of base64 string
val backupRecoveryKey = BackupRecoveryKey.fromBase64(info.recoveryKey)
return SavedKeyBackupKeyInfo(backupRecoveryKey, info.backupVersion)
}
/**

View file

@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
@ -469,7 +470,8 @@ internal class RealmCryptoStore @Inject constructor(
val key = it.keyBackupRecoveryKey
val version = it.keyBackupRecoveryKeyVersion
if (!key.isNullOrBlank() && !version.isNullOrBlank()) {
SavedKeyBackupKeyInfo(recoveryKey = key, version = version)
val backupRecoveryKey = BackupRecoveryKey.fromBase58(key)
SavedKeyBackupKeyInfo(recoveryKey = backupRecoveryKey, version = version)
} else {
null
}

View file

@ -520,10 +520,9 @@ internal class RoomSyncHandler @Inject constructor(
private fun decryptIfNeeded(event: Event, roomId: String) {
try {
// Event from sync does not have roomId, so add it to the event first
// note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching
val result = runBlocking {
cryptoService.decryptEvent(event.copy(roomId = roomId), "")
cryptoService.decryptEvent(event, "")
}
event.mxDecryptionResult = OlmDecryptionResult(
payload = result.clearEvent,

View file

@ -23,6 +23,7 @@ import im.vector.app.core.platform.WaitingViewData
import im.vector.app.core.resources.StringProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import javax.inject.Inject
class KeysBackupRestoreFromKeyViewModel @Inject constructor(
@ -42,7 +43,7 @@ class KeysBackupRestoreFromKeyViewModel @Inject constructor(
sharedViewModel.loadingEvent.postValue(WaitingViewData(stringProvider.getString(R.string.loading)))
recoveryCodeErrorText.value = null
viewModelScope.launch(Dispatchers.IO) {
val recoveryKey = recoveryCode.value!!
val recoveryKey = BackupRecoveryKey.fromBase58(recoveryCode.value!!)
try {
sharedViewModel.recoverUsingBackupRecoveryKey(recoveryKey)
} catch (failure: Throwable) {

View file

@ -31,6 +31,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.listeners.StepProgressListener
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
@ -88,7 +89,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
private val progressObserver = object : StepProgressListener {
override fun onStepProgress(step: StepProgressListener.Step) {
when (step) {
is StepProgressListener.Step.ComputingKey -> {
is StepProgressListener.Step.ComputingKey -> {
loadingEvent.postValue(
WaitingViewData(
stringProvider.getString(R.string.keys_backup_restoring_waiting_message) +
@ -107,7 +108,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
)
)
}
is StepProgressListener.Step.ImportingKey -> {
is StepProgressListener.Step.ImportingKey -> {
Timber.d("backupKeys.ImportingKey.progress: ${step.progress}")
// Progress 0 can take a while, display an indeterminate progress in this case
if (step.progress == 0) {
@ -131,14 +132,22 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
}
is StepProgressListener.Step.DecryptingKey -> {
if (step.progress == 0) {
loadingEvent.postValue(WaitingViewData(stringProvider.getString(R.string.keys_backup_restoring_waiting_message) +
"\n" + stringProvider.getString(R.string.keys_backup_restoring_decrypting_keys_waiting_message),
isIndeterminate = true))
loadingEvent.postValue(
WaitingViewData(
stringProvider.getString(R.string.keys_backup_restoring_waiting_message) +
"\n" + stringProvider.getString(R.string.keys_backup_restoring_decrypting_keys_waiting_message),
isIndeterminate = true
)
)
} else {
loadingEvent.postValue(WaitingViewData(stringProvider.getString(R.string.keys_backup_restoring_waiting_message) +
"\n" + stringProvider.getString(R.string.keys_backup_restoring_decrypting_keys_waiting_message),
step.progress,
step.total))
loadingEvent.postValue(
WaitingViewData(
stringProvider.getString(R.string.keys_backup_restoring_waiting_message) +
"\n" + stringProvider.getString(R.string.keys_backup_restoring_decrypting_keys_waiting_message),
step.progress,
step.total
)
)
}
}
}
@ -170,7 +179,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
)
// Go and use it!!
try {
recoverUsingBackupRecoveryKey(computeRecoveryKey(savedSecret.recoveryKey.fromBase64()), version)
recoverUsingBackupRecoveryKey(savedSecret.recoveryKey, version)
} catch (failure: Throwable) {
Timber.e(failure, "## recoverUsingBackupRecoveryKey FAILED")
keySourceModel.postValue(
@ -212,7 +221,9 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
viewModelScope.launch(Dispatchers.IO) {
try {
recoverUsingBackupRecoveryKey(computeRecoveryKey(secret.fromBase64()))
val computedRecoveryKey = computeRecoveryKey(secret.fromBase64())
val backupRecoveryKey = BackupRecoveryKey.fromBase58(computedRecoveryKey)
recoverUsingBackupRecoveryKey(backupRecoveryKey)
} catch (failure: Throwable) {
_navigateEvent.postValue(
LiveEvent(NAVIGATE_FAILED_TO_LOAD_4S)
@ -234,7 +245,8 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
loadingEvent.postValue(WaitingViewData(stringProvider.getString(R.string.loading)))
try {
val result = keysBackup.restoreKeyBackupWithPassword(keyVersion,
val result = keysBackup.restoreKeyBackupWithPassword(
keyVersion,
passphrase,
null,
session.myUserId,
@ -249,7 +261,7 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
}
}
suspend fun recoverUsingBackupRecoveryKey(recoveryKey: String, keyVersion: KeysVersionResult? = null) {
suspend fun recoverUsingBackupRecoveryKey(recoveryKey: BackupRecoveryKey, keyVersion: KeysVersionResult? = null) {
val keysBackup = session.cryptoService().keysBackupService()
// This is badddddd
val version = keyVersion ?: keyVersionResult.value ?: return
@ -257,7 +269,8 @@ class KeysBackupRestoreSharedViewModel @Inject constructor(
loadingEvent.postValue(WaitingViewData(stringProvider.getString(R.string.loading)))
try {
val result = keysBackup.restoreKeysWithRecoveryKey(version,
val result = keysBackup.restoreKeysWithRecoveryKey(
version,
recoveryKey,
null,
session.myUserId,

View file

@ -27,6 +27,7 @@ import im.vector.app.core.time.Clock
import im.vector.app.core.utils.LiveEvent
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
@ -71,7 +72,7 @@ class KeysBackupSetupSharedViewModel @Inject constructor(
// Step 3
// Var to ignore events from previous request(s) to generate a recovery key
private var currentRequestId: MutableLiveData<Long> = MutableLiveData()
var recoveryKey: MutableLiveData<String?> = MutableLiveData(null)
var recoveryKey: MutableLiveData<BackupRecoveryKey?> = MutableLiveData(null)
var prepareRecoverFailError: MutableLiveData<Throwable?> = MutableLiveData(null)
var megolmBackupCreationInfo: MegolmBackupCreationInfo? = null
var copyHasBeenMade = false

View file

@ -66,7 +66,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
views.keysBackupSetupStep3Label2.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)
views.keysBackupSetupStep3FinishButton.text = getString(R.string.keys_backup_setup_step3_button_title_no_passphrase)
views.keysBackupSetupStep3RecoveryKeyText.text = viewModel.recoveryKey.value!!
views.keysBackupSetupStep3RecoveryKeyText.text = viewModel.recoveryKey.value!!.toBase58()
.replace(" ", "")
.chunked(16)
.joinToString("\n") {
@ -114,7 +114,8 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
} else {
dialog.findViewById<TextView>(R.id.keys_backup_recovery_key_text)?.let {
it.isVisible = true
it.text = recoveryKey.replace(" ", "")
it.text = recoveryKey.toBase58()
.replace(" ", "")
.chunked(16)
.joinToString("\n") {
it
@ -123,7 +124,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
}
it.debouncedClicks {
copyToClipboard(requireActivity(), recoveryKey)
copyToClipboard(requireActivity(), recoveryKey.toBase58())
}
}
}
@ -145,7 +146,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
fragment = this,
activityResultLauncher = null,
chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
text = recoveryKey,
text = recoveryKey.toBase58(),
subject = context?.getString(R.string.recovery_key)
)
viewModel.copyHasBeenMade = true
@ -159,7 +160,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
viewModel.recoveryKey.value?.let {
viewModel.copyHasBeenMade = true
copyToClipboard(requireActivity(), it)
copyToClipboard(requireActivity(), it.toBase58())
}
}
@ -202,7 +203,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
val uri = activityRessult.data?.data ?: return@registerStartForActivityResult
if (activityRessult.resultCode == Activity.RESULT_OK) {
viewModel.recoveryKey.value?.let {
exportRecoveryKeyToFile(uri, it)
exportRecoveryKeyToFile(uri, it.toBase58())
}
}
}

View file

@ -23,6 +23,7 @@ import im.vector.app.core.resources.StringProvider
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
import org.matrix.android.sdk.api.session.securestorage.EmptyKeySigner
@ -91,8 +92,8 @@ class BackupToQuadSMigrationTask @Inject constructor(
reportProgress(params, R.string.bootstrap_progress_compute_curve_key)
val recoveryKey = computeRecoveryKey(curveKey)
val isValid = keysBackupService.isValidRecoveryKeyForCurrentVersion(recoveryKey)
val backupRecoveryKey = BackupRecoveryKey.fromBase58(recoveryKey)
val isValid = keysBackupService.isValidRecoveryKeyForCurrentVersion(backupRecoveryKey)
if (!isValid) return Result.InvalidRecoverySecret
@ -143,7 +144,7 @@ class BackupToQuadSMigrationTask @Inject constructor(
)
// save for gossiping
keysBackupService.saveBackupRecoveryKey(recoveryKey, version.version)
keysBackupService.saveBackupRecoveryKey(backupRecoveryKey, version.version)
// It's not a good idea to download the full backup, it might take very long
// and use a lot of resources
return Result.Success

View file

@ -236,7 +236,7 @@ class BootstrapCrossSigningTask @Inject constructor(
Timber.d("## BootstrapCrossSigningTask: Creating 4S - Save megolm backup key for gossiping")
session.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey)?.toBase64NoPadding()?.let { secret ->
extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey.toBase58())?.toBase64NoPadding()?.let { secret ->
ssssService.storeSecret(
KEYBACKUP_SECRET_SSSS_NAME,
secret,
@ -251,7 +251,7 @@ class BootstrapCrossSigningTask @Inject constructor(
val isValid = session.cryptoService().keysBackupService().isValidRecoveryKeyForCurrentVersion(knownMegolmSecret!!.recoveryKey)
if (isValid) {
Timber.d("## BootstrapCrossSigningTask: Creating 4S - Megolm key valid and known")
extractCurveKeyFromRecoveryKey(knownMegolmSecret.recoveryKey)?.toBase64NoPadding()?.let { secret ->
extractCurveKeyFromRecoveryKey(knownMegolmSecret.recoveryKey.toBase58())?.toBase64NoPadding()?.let { secret ->
ssssService.storeSecret(
KEYBACKUP_SECRET_SSSS_NAME,
secret,

View file

@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NA
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
import org.matrix.android.sdk.api.session.crypto.verification.CancelCode
@ -431,9 +432,10 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
val version = session.cryptoService().keysBackupService().getCurrentVersion()?.toKeysVersionResult() ?: return@launch
val recoveryKey = computeRecoveryKey(secret.fromBase64())
val isValid = session.cryptoService().keysBackupService().isValidRecoveryKeyForCurrentVersion(recoveryKey)
val backupRecoveryKey = BackupRecoveryKey.fromBase58(recoveryKey)
val isValid = session.cryptoService().keysBackupService().isValidRecoveryKeyForCurrentVersion(backupRecoveryKey)
if (isValid) {
session.cryptoService().keysBackupService().saveBackupRecoveryKey(recoveryKey, version.version)
session.cryptoService().keysBackupService().saveBackupRecoveryKey(backupRecoveryKey, version.version)
}
session.cryptoService().keysBackupService().trustKeysBackupVersion(version, true)
} catch (failure: Throwable) {
@ -502,6 +504,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
}
override fun transactionUpdated(tx: VerificationTransaction) = withState { state ->
Timber.v("transactionUpdated: $tx")
handleTransactionUpdate(state, tx)
}
@ -510,7 +513,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
}
override fun verificationRequestUpdated(pr: PendingVerificationRequest) = withState { state ->
Timber.v("VerificationRequestUpdated: $pr")
if (state.selfVerificationMode && state.pendingRequest.invoke() == null && state.transactionId == null) {
// is this an incoming with that user
if (pr.isIncoming && pr.otherUserId == state.otherUserMxItem?.id) {