Skip to content

Commit c055f40

Browse files
ganfraBillCarsonFr
authored andcommitted
Backup: refactor to extract everything related to specific algorithm
1 parent f855664 commit c055f40

26 files changed

+790
-417
lines changed

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
2525
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
2626
import org.matrix.android.sdk.api.auth.UserPasswordAuth
2727
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
28-
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
2928
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_CURVE_25519_BACKUP
29+
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
3030
import org.matrix.android.sdk.api.extensions.orFalse
3131
import org.matrix.android.sdk.api.session.Session
3232
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
@@ -35,8 +35,8 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NA
3535
import org.matrix.android.sdk.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
3636
import org.matrix.android.sdk.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
3737
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
38-
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
3938
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
39+
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCurve25519AuthData
4040
import org.matrix.android.sdk.api.session.crypto.keysbackup.extractCurveKeyFromRecoveryKey
4141
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
4242
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
@@ -179,8 +179,35 @@ class CryptoTestHelper(val testHelper: CommonTestHelper) {
179179
}
180180
}
181181

182-
private fun createFakeMegolmBackupAuthData(): MegolmBackupAuthData {
183-
return MegolmBackupAuthData(
182+
fun checkEncryptedEvent(event: Event, roomId: String, clearMessage: String, senderSession: Session) {
183+
assertEquals(EventType.ENCRYPTED, event.type)
184+
assertNotNull(event.content)
185+
186+
val eventWireContent = event.content.toContent()
187+
assertNotNull(eventWireContent)
188+
189+
assertNull(eventWireContent["body"])
190+
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM, eventWireContent["algorithm"])
191+
192+
assertNotNull(eventWireContent["ciphertext"])
193+
assertNotNull(eventWireContent["session_id"])
194+
assertNotNull(eventWireContent["sender_key"])
195+
196+
assertEquals(senderSession.sessionParams.deviceId, eventWireContent["device_id"])
197+
198+
assertNotNull(event.eventId)
199+
assertEquals(roomId, event.roomId)
200+
assertEquals(EventType.MESSAGE, event.getClearType())
201+
// TODO assertTrue(event.getAge() < 10000)
202+
203+
val eventContent = event.toContent()
204+
assertNotNull(eventContent)
205+
assertEquals(clearMessage, eventContent["body"])
206+
assertEquals(senderSession.myUserId, event.senderId)
207+
}
208+
209+
fun createFakeMegolmBackupAuthData(): MegolmBackupCurve25519AuthData {
210+
return MegolmBackupCurve25519AuthData(
184211
publicKey = "abcdefg",
185212
signatures = mapOf("something" to mapOf("ed25519:something" to "hijklmnop"))
186213
)
@@ -288,6 +315,24 @@ class CryptoTestHelper(val testHelper: CommonTestHelper) {
288315
secret,
289316
listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
290317
)
318+
319+
// set up megolm backup
320+
val creationInfo = awaitCallback<MegolmBackupCreationInfo> {
321+
session.cryptoService().keysBackupService().prepareKeysBackupVersion(null, null, null, it)
322+
}
323+
val version = awaitCallback<KeysVersion> {
324+
session.cryptoService().keysBackupService().createKeysBackupVersion(creationInfo, it)
325+
}
326+
// Save it for gossiping
327+
session.cryptoService().keysBackupService().saveBackupRecoveryKey(creationInfo.recoveryKey, version = version.version)
328+
329+
extractCurveKeyFromRecoveryKey(creationInfo.recoveryKey)?.toBase64NoPadding()?.let { secret ->
330+
ssssService.storeSecret(
331+
KEYBACKUP_SECRET_SSSS_NAME,
332+
secret,
333+
listOf(KeyRef(keyInfo.keyId, keyInfo.keySpec))
334+
)
335+
}
291336
}
292337
}
293338

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2EShareKeysConfigTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class E2EShareKeysConfigTest : InstrumentedTest {
218218
val keysBackupService = aliceSession.cryptoService().keysBackupService()
219219
val keyBackupPassword = "FooBarBaz"
220220
val megolmBackupCreationInfo = commonTestHelper.waitForCallback<MegolmBackupCreationInfo> {
221-
keysBackupService.prepareKeysBackupVersion(keyBackupPassword, null, it)
221+
keysBackupService.prepareKeysBackupVersion(keyBackupPassword, null, null, it)
222222
}
223223
val version = commonTestHelper.waitForCallback<KeysVersion> {
224224
keysBackupService.createKeysBackupVersion(megolmBackupCreationInfo, it)

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class E2eeSanityTests : InstrumentedTest {
224224
val bobKeysBackupService = bobSession.cryptoService().keysBackupService()
225225
val keyBackupPassword = "FooBarBaz"
226226
val megolmBackupCreationInfo = testHelper.waitForCallback<MegolmBackupCreationInfo> {
227-
bobKeysBackupService.prepareKeysBackupVersion(keyBackupPassword, null, it)
227+
bobKeysBackupService.prepareKeysBackupVersion(keyBackupPassword, null, null, it)
228228
}
229229
val version = testHelper.waitForCallback<KeysVersion> {
230230
bobKeysBackupService.createKeysBackupVersion(megolmBackupCreationInfo, it)

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTest.kt

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTru
4141
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
4242
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
4343
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
44+
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCurve25519AuthData
4445
import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult
4546
import org.matrix.android.sdk.api.session.crypto.model.ImportRoomKeysResult
4647
import org.matrix.android.sdk.api.session.getRoom
@@ -49,6 +50,10 @@ import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
4950
import org.matrix.android.sdk.common.RetryTestRule
5051
import org.matrix.android.sdk.common.TestConstants
5152
import org.matrix.android.sdk.common.waitFor
53+
import org.matrix.android.sdk.internal.crypto.keysbackup.algorithm.KeysBackupAlgorithmFactory
54+
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeyBackupData
55+
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysBackupData
56+
import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.RoomKeysBackupData
5257
import java.security.InvalidParameterException
5358
import java.util.Collections
5459
import java.util.concurrent.CountDownLatch
@@ -119,11 +124,12 @@ class KeysBackupTest : InstrumentedTest {
119124
assertFalse(keysBackup.isEnabled())
120125

121126
val megolmBackupCreationInfo = testHelper.waitForCallback<MegolmBackupCreationInfo> {
122-
keysBackup.prepareKeysBackupVersion(null, null, it)
127+
keysBackup.prepareKeysBackupVersion(null, null, null, it)
123128
}
124129

125130
assertEquals(MXCRYPTO_ALGORITHM_CURVE_25519_BACKUP, megolmBackupCreationInfo.algorithm)
126-
assertNotNull(megolmBackupCreationInfo.authData.publicKey)
131+
val authData = megolmBackupCreationInfo.authData as MegolmBackupCurve25519AuthData
132+
assertNotNull(authData.publicKey)
127133
assertNotNull(megolmBackupCreationInfo.authData.signatures)
128134
assertNotNull(megolmBackupCreationInfo.recoveryKey)
129135

@@ -145,7 +151,7 @@ class KeysBackupTest : InstrumentedTest {
145151
assertFalse(keysBackup.isEnabled())
146152

147153
val megolmBackupCreationInfo = testHelper.waitForCallback<MegolmBackupCreationInfo> {
148-
keysBackup.prepareKeysBackupVersion(null, null, it)
154+
keysBackup.prepareKeysBackupVersion(null, null, null, it)
149155
}
150156

151157
assertFalse(keysBackup.isEnabled())
@@ -298,23 +304,25 @@ class KeysBackupTest : InstrumentedTest {
298304
val session = keysBackup.store.inboundGroupSessionsToBackup(1)[0]
299305

300306
val keyBackupCreationInfo = keysBackupTestHelper.prepareAndCreateKeysBackupData(keysBackup).megolmBackupCreationInfo
301-
307+
val keysBackupVersion = keysBackup.keysBackupVersion
308+
assertNotNull(keysBackupVersion)
309+
val algorithm = KeysBackupAlgorithmFactory().create(keysBackupVersion!!)
302310
// - Check encryptGroupSession() returns stg
303311
val keyBackupData = keysBackup.encryptGroupSession(session)
304312
assertNotNull(keyBackupData)
305313
assertNotNull(keyBackupData!!.sessionData)
306-
307-
// - Check pkDecryptionFromRecoveryKey() is able to create a OlmPkDecryption
308-
val decryption = keysBackup.pkDecryptionFromRecoveryKey(keyBackupCreationInfo.recoveryKey)
309-
assertNotNull(decryption)
310-
// - Check decryptKeyBackupData() returns stg
311-
val sessionData = keysBackup
312-
.decryptKeyBackupData(
313-
keyBackupData,
314-
session.safeSessionId!!,
315-
cryptoTestData.roomId,
316-
decryption!!
317-
)
314+
val roomKeysBackupData = RoomKeysBackupData(
315+
HashMap<String, KeyBackupData>().apply {
316+
put(session.safeSessionId!!, keyBackupData)
317+
}
318+
)
319+
val keysBackupData = KeysBackupData(
320+
HashMap<String, RoomKeysBackupData>().apply {
321+
put(cryptoTestData.roomId, roomKeysBackupData)
322+
}
323+
)
324+
val sessionsData = algorithm.decryptSessions(keyBackupCreationInfo.recoveryKey, keysBackupData)
325+
val sessionData = sessionsData.firstOrNull()
318326
assertNotNull(sessionData)
319327
// - Compare the decrypted megolm key with the original one
320328
keysBackupTestHelper.assertKeysEquals(session.exportKeys(), sessionData)

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/keysbackup/KeysBackupTestHelper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ internal class KeysBackupTestHelper(
105105
val stateObserver = StateObserver(keysBackup)
106106

107107
val megolmBackupCreationInfo = testHelper.waitForCallback<MegolmBackupCreationInfo> {
108-
keysBackup.prepareKeysBackupVersion(password, null, it)
108+
keysBackup.prepareKeysBackupVersion(password, null, null, it)
109109
}
110110

111111
Assert.assertNotNull(megolmBackupCreationInfo)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysBackupService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ interface KeysBackupService {
124124
*/
125125
fun prepareKeysBackupVersion(
126126
password: String?,
127+
algorithm: String? = null,
127128
progressListener: ProgressListener?,
128129
callback: MatrixCallback<MegolmBackupCreationInfo>
129130
)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/KeysVersionResult.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorith
2424
@JsonClass(generateAdapter = true)
2525
data class KeysVersionResult(
2626
/**
27-
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
27+
* The algorithm used for storing backups.
28+
* Currently, "m.megolm_backup.v1.curve25519-aes-sha2" and
29+
* org.matrix.msc3270.v1.aes-hmac-sha2 are defined.
2830
*/
2931
@Json(name = "algorithm")
3032
override val algorithm: String,
3133

3234
/**
3335
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2".
34-
* @see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
36+
* @see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupCurve25519AuthData]
3537
*/
3638
@Json(name = "auth_data")
3739
override val authData: JsonDict,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2020 The Matrix.org Foundation C.I.C.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.matrix.android.sdk.api.session.crypto.keysbackup
18+
19+
import com.squareup.moshi.Json
20+
import com.squareup.moshi.JsonClass
21+
import org.matrix.android.sdk.api.util.JsonDict
22+
import org.matrix.android.sdk.internal.di.MoshiProvider
23+
24+
/**
25+
* Data model for [org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysAlgorithmAndData.authData] in case
26+
* of [org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_AES_256_BACKUP].
27+
*/
28+
@JsonClass(generateAdapter = true)
29+
data class MegolmBackupAes256AuthData(
30+
31+
/**
32+
* The identity vector used to encrypt the backups.
33+
*/
34+
@Json(name = "iv")
35+
val iv: String? = null,
36+
37+
/**
38+
* The mac used to encrypt the backups.
39+
*/
40+
@Json(name = "mac")
41+
val mac: String? = null,
42+
43+
/**
44+
* In case of a backup created from a password, the salt associated with the backup
45+
* private key.
46+
*/
47+
@Json(name = "private_key_salt")
48+
override val privateKeySalt: String? = null,
49+
50+
/**
51+
* In case of a backup created from a password, the number of key derivations.
52+
*/
53+
@Json(name = "private_key_iterations")
54+
override val privateKeyIterations: Int? = null,
55+
56+
/**
57+
* Signatures of the public key.
58+
* userId -> (deviceSignKeyId -> signature)
59+
*/
60+
@Json(name = "signatures")
61+
override val signatures: Map<String, Map<String, String>>? = null
62+
63+
) : MegolmBackupAuthData {
64+
65+
override fun isValid(): Boolean = !(iv.isNullOrEmpty() || mac.isNullOrEmpty())
66+
67+
override fun copy(newSignatures: Map<String, Map<String, String>>?): MegolmBackupAuthData {
68+
return copy(signatures = newSignatures)
69+
}
70+
71+
override fun toJsonDict(): JsonDict {
72+
val moshi = MoshiProvider.providesMoshi()
73+
val adapter = moshi.adapter(Map::class.java)
74+
75+
return moshi
76+
.adapter(MegolmBackupAes256AuthData::class.java)
77+
.toJson(this)
78+
.let {
79+
@Suppress("UNCHECKED_CAST")
80+
adapter.fromJson(it) as JsonDict
81+
}
82+
}
83+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/keysbackup/MegolmBackupAuthData.kt

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,64 +16,15 @@
1616

1717
package org.matrix.android.sdk.api.session.crypto.keysbackup
1818

19-
import com.squareup.moshi.Json
20-
import com.squareup.moshi.JsonClass
2119
import org.matrix.android.sdk.api.util.JsonDict
22-
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
23-
import org.matrix.android.sdk.internal.di.MoshiProvider
2420

25-
/**
26-
* Data model for [org.matrix.androidsdk.rest.model.keys.KeysAlgorithmAndData.authData] in case
27-
* of [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
28-
*/
29-
@JsonClass(generateAdapter = true)
30-
data class MegolmBackupAuthData(
31-
/**
32-
* The curve25519 public key used to encrypt the backups.
33-
*/
34-
@Json(name = "public_key")
35-
val publicKey: String,
36-
37-
/**
38-
* In case of a backup created from a password, the salt associated with the backup
39-
* private key.
40-
*/
41-
@Json(name = "private_key_salt")
42-
val privateKeySalt: String? = null,
43-
44-
/**
45-
* In case of a backup created from a password, the number of key derivations.
46-
*/
47-
@Json(name = "private_key_iterations")
48-
val privateKeyIterations: Int? = null,
49-
50-
/**
51-
* Signatures of the public key.
52-
* userId -> (deviceSignKeyId -> signature)
53-
*/
54-
@Json(name = "signatures")
55-
val signatures: Map<String, Map<String, String>>? = null
56-
) {
57-
58-
internal fun toJsonDict(): JsonDict {
59-
val moshi = MoshiProvider.providesMoshi()
60-
val adapter = moshi.adapter(Map::class.java)
21+
sealed interface MegolmBackupAuthData {
22+
val privateKeySalt: String?
23+
val privateKeyIterations: Int?
24+
val signatures: Map<String, Map<String, String>>?
6125

62-
return moshi
63-
.adapter(MegolmBackupAuthData::class.java)
64-
.toJson(this)
65-
.let {
66-
@Suppress("UNCHECKED_CAST")
67-
adapter.fromJson(it) as JsonDict
68-
}
69-
}
26+
fun isValid(): Boolean
7027

71-
internal fun signalableJSONDictionary(): JsonDict {
72-
return SignalableMegolmBackupAuthData(
73-
publicKey = publicKey,
74-
privateKeySalt = privateKeySalt,
75-
privateKeyIterations = privateKeyIterations
76-
)
77-
.signalableJSONDictionary()
78-
}
28+
fun toJsonDict(): JsonDict
29+
fun copy(newSignatures: Map<String, Map<String, String>>?): MegolmBackupAuthData
7930
}

0 commit comments

Comments
 (0)