Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1ed8748
update radix version
DelmoreCooper Sep 14, 2023
a86cc21
e2e
DelmoreCooper Dec 1, 2023
6e31ac1
support algorithm of MXCRYPTO_ALGORITHM_RATCHET
DelmoreCooper Dec 6, 2023
584a7ba
update app
DelmoreCooper Dec 7, 2023
19c2200
forward room key if algorithm is MXCRYPTO_ALGORITHM_RATCHET
DelmoreCooper Dec 13, 2023
2f35c27
add debug log
DelmoreCooper Dec 13, 2023
8386d2f
support rerequest decryption key
DelmoreCooper Dec 18, 2023
d5033b7
use adaptive encryption
DelmoreCooper Dec 22, 2023
665fa2a
remove current session if room memeber device changed
DelmoreCooper Dec 27, 2023
1b42181
crypto: skip requesting keys for old event
DelmoreCooper Jan 3, 2024
f0c3195
crypto: optionally clear storage on logout
DelmoreCooper Jan 5, 2024
2add973
crypto: reuse deviceId & add traceId
DelmoreCooper Jan 11, 2024
f4513d2
crypto: support pull keys by sessionId
DelmoreCooper Feb 3, 2024
55eb2cf
crypto: share key from ratchet encryption
DelmoreCooper Feb 25, 2024
f35fc29
crypto: skip encrypting event for large room
DelmoreCooper Feb 29, 2024
be94e41
crypto: support new ratchet encryption
DelmoreCooper Mar 21, 2024
3cb68b7
crypto: skip query keys in large room
DelmoreCooper Apr 11, 2024
c62bea9
crypto: fix deviceId bug
DelmoreCooper Apr 29, 2024
2b5ae2d
update radix version
DelmoreCooper Jul 17, 2024
58302df
crypto: direct share key
DelmoreCooper Jun 28, 2024
ecc1aa8
crypto: fix query shared session
DelmoreCooper Jul 30, 2024
595a51e
crypto: fix accept forward key
DelmoreCooper Aug 7, 2024
92e84bc
crypto: direct send key request to device
DelmoreCooper Aug 14, 2024
c9620aa
crypto: fix room key reply
DelmoreCooper Aug 22, 2024
43e48d1
feat: add lib realmfieldnameshelper
DelmoreCooper Oct 15, 2024
d49f084
crypto: optimize key share
DelmoreCooper Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ext.versions = [
'minSdk' : 21,
'minSdk' : 23,
'compileSdk' : 33,
'targetSdk' : 33,
'sourceCompat' : JavaVersion.VERSION_11,
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official

vector.debugPrivateData=false
vector.debugPrivateData=true
vector.httpLogLevel=NONE

android.experimental.legacyTransform.forceNonIncremental=true
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@
package org.sdn.android.sdk.api.crypto

/**
* Matrix algorithm value for olm.
* Algorithm value for olm.
*/
const val MXCRYPTO_ALGORITHM_OLM = "m.olm.v1.curve25519-aes-sha2"

/**
* Matrix algorithm value for megolm.
* Algorithm value for megolm.
*/
const val MXCRYPTO_ALGORITHM_MEGOLM = "m.megolm.v1.aes-sha2"

/**
* Matrix algorithm value for megolm keys backup.
* Algorithm value for ratchet.
*/
const val MXCRYPTO_ALGORITHM_RATCHET = "m.megolm.v1.aes-ratchet"

/**
* Algorithm value for megolm keys backup.
*/
const val MXCRYPTO_ALGORITHM_MEGOLM_BACKUP = "m.megolm_backup.v1.curve25519-aes-sha2"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ data class MXCryptoConfig constructor(
* You can limit request only to your sessions by turning this setting to `true`.
* Forwarded keys coming from other users will also be ignored if set to true.
*/
val limitRoomKeyRequestsToMyDevices: Boolean = true,
val limitRoomKeyRequestsToMyDevices: Boolean = false,

)
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
package org.sdn.android.sdk.api.session.room.model

import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET

sealed class RoomEncryptionAlgorithm {

abstract class SupportedAlgorithm(val alg: String) : RoomEncryptionAlgorithm()

object Megolm : SupportedAlgorithm(MXCRYPTO_ALGORITHM_MEGOLM)
object Ratchet : SupportedAlgorithm(MXCRYPTO_ALGORITHM_RATCHET)

data class UnsupportedAlgorithm(val name: String?) : RoomEncryptionAlgorithm()
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ open class CreateRoomParams {
var historyVisibility: RoomHistoryVisibility? = null

fun enableEncryption() {
// TODO add support for MXCRYPTO_ALGORITHM_RATCHET
algorithm = MXCRYPTO_ALGORITHM_MEGOLM
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.sdn.android.sdk.api.SDNCallback
import org.sdn.android.sdk.api.SDNCoroutineDispatchers
import org.sdn.android.sdk.api.NoOpSDNCallback
import org.sdn.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
import org.sdn.android.sdk.api.crypto.MXCryptoConfig
Expand Down Expand Up @@ -79,6 +80,7 @@ import org.sdn.android.sdk.internal.crypto.actions.MegolmSessionDataImporter
import org.sdn.android.sdk.internal.crypto.actions.SetDeviceVerificationAction
import org.sdn.android.sdk.internal.crypto.algorithms.IMXEncrypting
import org.sdn.android.sdk.internal.crypto.algorithms.IMXGroupEncryption
import org.sdn.android.sdk.internal.crypto.algorithms.megolm.MXRatchetEncryptionFactory
import org.sdn.android.sdk.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
import org.sdn.android.sdk.internal.crypto.algorithms.megolm.UnRequestedForwardManager
import org.sdn.android.sdk.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
Expand Down Expand Up @@ -170,6 +172,7 @@ internal class DefaultCryptoService @Inject constructor(
private val megolmSessionDataImporter: MegolmSessionDataImporter,
private val warnOnUnknownDevicesRepository: WarnOnUnknownDeviceRepository,
// Repository
private val ratchetEncryptionFactory: MXRatchetEncryptionFactory,
private val megolmEncryptionFactory: MXMegolmEncryptionFactory,
private val olmEncryptionFactory: MXOlmEncryptionFactory,
// Tasks
Expand Down Expand Up @@ -513,7 +516,7 @@ internal class DefaultCryptoService @Inject constructor(
* @return the device info, or null if not found / unsupported algorithm / crypto released
*/
override fun deviceWithIdentityKey(senderKey: String, algorithm: String): CryptoDeviceInfo? {
return if (algorithm != MXCRYPTO_ALGORITHM_MEGOLM && algorithm != MXCRYPTO_ALGORITHM_OLM) {
return if (algorithm != MXCRYPTO_ALGORITHM_RATCHET && algorithm != MXCRYPTO_ALGORITHM_MEGOLM && algorithm != MXCRYPTO_ALGORITHM_OLM) {
// We only deal in olm keys
null
} else cryptoStore.deviceWithIdentityKey(senderKey)
Expand Down Expand Up @@ -646,6 +649,7 @@ internal class DefaultCryptoService @Inject constructor(
}

val alg: IMXEncrypting? = when (algorithm) {
MXCRYPTO_ALGORITHM_RATCHET -> ratchetEncryptionFactory.create(roomId)
MXCRYPTO_ALGORITHM_MEGOLM -> megolmEncryptionFactory.create(roomId)
MXCRYPTO_ALGORITHM_OLM -> olmEncryptionFactory.create(roomId)
else -> null
Expand Down Expand Up @@ -676,10 +680,10 @@ internal class DefaultCryptoService @Inject constructor(
}

/**
* Tells if a room is encrypted with MXCRYPTO_ALGORITHM_MEGOLM.
* Tells if a room is encrypted.
*
* @param roomId the room id
* @return true if the room is encrypted with algorithm MXCRYPTO_ALGORITHM_MEGOLM
* @return true if the room is encrypted
*/
override fun isRoomEncrypted(roomId: String): Boolean {
return cryptoSessionInfoProvider.isRoomEncrypted(roomId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ internal class DeviceListManager @Inject constructor(
}

if (isUpdated) {
Timber.v("## CRYPTO: removeCurrentGroupSession on device changed")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm while isUpdated=true is equivalent to the scenarios mentioned by @auruac

cryptoStore.removeAllCurrentGroupSession()
cryptoStore.saveDeviceTrackingStatuses(deviceTrackingStatuses)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import kotlinx.coroutines.withContext
import org.sdn.android.sdk.api.SDNCoroutineDispatchers
import org.sdn.android.sdk.api.auth.data.Credentials
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET
import org.sdn.android.sdk.api.crypto.MXCryptoConfig
import org.sdn.android.sdk.api.extensions.tryOrNull
import org.sdn.android.sdk.api.logger.LoggerTag
Expand Down Expand Up @@ -85,6 +86,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
val roomId: String,
val senderKey: String,
val sessionId: String,
val algorithm: String,
val action: MegolmRequestAction
) {
fun shortDbgString() = "Request from $requestingUserId|$requestingDeviceId for session $sessionId in room $roomId"
Expand All @@ -97,7 +99,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
val sessionId = body.sessionId ?: return null
val senderKey = body.senderKey ?: return null
val requestId = this.requestId ?: return null
if (body.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
if (!arrayOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_RATCHET).contains(body.algorithm)) return null
val action = when (this.action) {
"request" -> MegolmRequestAction.Request
"request_cancellation" -> MegolmRequestAction.Cancel
Expand All @@ -110,6 +112,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
roomId = roomId,
senderKey = senderKey,
sessionId = sessionId,
algorithm = body.algorithm!!,
action = action
)
}
Expand Down Expand Up @@ -217,15 +220,15 @@ internal class IncomingKeyRequestManager @Inject constructor(
request.roomId,
request.sessionId,
request.senderKey,
MXCRYPTO_ALGORITHM_MEGOLM,
request.algorithm,
request.requestingUserId,
request.requestingDeviceId
)

val roomAlgorithm = // withContext(coroutineDispatchers.crypto) {
cryptoStore.getRoomAlgorithm(request.roomId)
// }
if (roomAlgorithm != MXCRYPTO_ALGORITHM_MEGOLM) {
if (!arrayOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_RATCHET).contains(roomAlgorithm)) {
// strange we received a request for a room that is not encrypted
// maybe a broken state?
Timber.tag(loggerTag.value).w("Received a key request in a room with unsupported alg:$roomAlgorithm , req:${request.shortDbgString()}")
Expand Down Expand Up @@ -285,7 +288,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
deviceId = requestingDevice.deviceId,
requestId = request.requestId,
requestBody = RoomKeyRequestBody(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
algorithm = request.algorithm,
senderKey = request.senderKey,
sessionId = request.sessionId,
roomId = request.roomId
Expand All @@ -308,7 +311,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
val withHeldContent = RoomKeyWithHeldContent(
roomId = request.roomId,
senderKey = request.senderKey,
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
algorithm = request.algorithm,
sessionId = request.sessionId,
codeString = code.value,
fromDevice = credentials.deviceId
Expand All @@ -331,7 +334,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
roomId = request.roomId,
sessionId = request.sessionId,
senderKey = request.senderKey,
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
algorithm = request.algorithm,
code = code,
userId = request.requestingUserId,
deviceId = request.requestingDeviceId
Expand All @@ -358,6 +361,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
roomId = request.requestBody.roomId,
senderKey = request.requestBody.senderKey,
sessionId = request.requestBody.sessionId,
algorithm = request.requestBody.algorithm ?: "",
action = MegolmRequestAction.Request
)
val requestingDevice =
Expand Down Expand Up @@ -429,7 +433,7 @@ internal class IncomingKeyRequestManager @Inject constructor(
validRequest.roomId,
validRequest.sessionId,
validRequest.senderKey,
MXCRYPTO_ALGORITHM_MEGOLM,
validRequest.algorithm,
requestingDevice.userId,
requestingDevice.deviceId,
chainIndex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package org.sdn.android.sdk.internal.crypto

import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_OLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET

// TODO Update comment
internal object MXCryptoAlgorithms {
Expand All @@ -30,6 +31,7 @@ internal object MXCryptoAlgorithms {
*/
fun hasEncryptorClassForAlgorithm(algorithm: String?): Boolean {
return when (algorithm) {
MXCRYPTO_ALGORITHM_RATCHET,
MXCRYPTO_ALGORITHM_MEGOLM,
MXCRYPTO_ALGORITHM_OLM -> true
else -> false
Expand All @@ -45,6 +47,7 @@ internal object MXCryptoAlgorithms {

fun hasDecryptorClassForAlgorithm(algorithm: String?): Boolean {
return when (algorithm) {
MXCRYPTO_ALGORITHM_RATCHET,
MXCRYPTO_ALGORITHM_MEGOLM,
MXCRYPTO_ALGORITHM_OLM -> true
else -> false
Expand All @@ -55,6 +58,6 @@ internal object MXCryptoAlgorithms {
* @return The list of registered algorithms.
*/
fun supportedAlgorithms(): List<String> {
return listOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM)
return listOf(MXCRYPTO_ALGORITHM_RATCHET, MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_OLM)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import org.matrix.olm.OlmMessage
import org.matrix.olm.OlmOutboundGroupSession
import org.matrix.olm.OlmSession
import org.matrix.olm.OlmUtility
import org.sdn.android.sdk.internal.crypto.algorithms.megolm.AESUtil
import timber.log.Timber
import javax.inject.Inject

Expand Down Expand Up @@ -610,6 +611,7 @@ internal class MXOlmDevice @Inject constructor(
sessionId: String,
sessionKey: String,
roomId: String,
algorithm: String,
senderKey: String,
forwardingCurve25519KeyChain: List<String>,
keysClaimed: Map<String, String>,
Expand Down Expand Up @@ -694,6 +696,7 @@ internal class MXOlmDevice @Inject constructor(
val candidateSessionData = InboundGroupSessionData(
senderKey = senderKey,
roomId = roomId,
algorithm = algorithm,
keysClaimed = keysClaimed,
forwardingCurve25519KeyChain = forwardingCurve25519KeyChain,
sharedHistory = sharedHistory,
Expand Down Expand Up @@ -860,6 +863,46 @@ internal class MXOlmDevice @Inject constructor(
)
}

@Throws(MXCryptoError::class)
suspend fun decryptRatchetMessage(
body: String,
roomId: String,
timeline: String?,
eventId: String,
sessionId: String,
senderKey: String
): OlmDecryptionResult {
val sessionHolder = getInboundGroupSession(sessionId, senderKey, roomId)
val wrapper = sessionHolder.wrapper
val inboundGroupSession = wrapper.session
if (roomId != wrapper.roomId) {
// Check that the room id matches the original one for the session. This stops
// the HS pretending a message was targeting a different room.
val reason = String.format(MXCryptoError.INBOUND_SESSION_MISMATCH_ROOM_ID_REASON, roomId, wrapper.roomId)
Timber.tag(loggerTag.value).e("## decryptGroupMessage() : $reason")
throw MXCryptoError.Base(MXCryptoError.ErrorType.INBOUND_SESSION_MISMATCH_ROOM_ID, reason)
}
val internalKey = inboundGroupSession.export(0)
val decryptedMessage = AESUtil.decrypt(internalKey.toByteArray().copyOfRange(0, 16), body)

val payload = try {
val adapter = MoshiProvider.providesMoshi().adapter<JsonDict>(JSON_DICT_PARAMETERIZED_TYPE)
val payloadString = convertFromUTF8(decryptedMessage)
adapter.fromJson(payloadString)
} catch (e: Exception) {
Timber.tag(loggerTag.value).e("## decryptGroupMessage() : fails to parse the payload")
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON)
}

return OlmDecryptionResult(
payload,
wrapper.sessionData.keysClaimed,
senderKey,
wrapper.sessionData.forwardingCurve25519KeyChain,
isSafe = sessionHolder.wrapper.sessionData.trusted.orFalse()
)
}

/**
* Reset replay attack data for the given timeline.
*
Expand Down Expand Up @@ -944,6 +987,21 @@ internal class MXOlmDevice @Inject constructor(
}
}

/**
* Extract the current InboundGroupSession from the session store
*
* @param roomId the room where the session is used.
* @return the inbound group session.
*/
fun getCurrentGroupSession(roomId: String): InboundGroupSessionHolder? {

val session = store.getCurrentGroupSession(roomId)
if (session != null) {
return InboundGroupSessionHolder(session)
}
return null
}

/**
* Determine if we have the keys for a given megolm session.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.sdn.android.sdk.api.SDNCoroutineDispatchers
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.sdn.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_RATCHET
import org.sdn.android.sdk.api.crypto.MXCryptoConfig
import org.sdn.android.sdk.api.extensions.tryOrNull
import org.sdn.android.sdk.api.logger.LoggerTag
Expand Down Expand Up @@ -94,7 +95,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(
val encryptedEventContent = event.content.toModel<EncryptedEventContent>() ?: return null.also {
Timber.tag(loggerTag.value).e("getRoomKeyRequestTargetForEvent Failed to re-request key, null content")
}
if (encryptedEventContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
if (!arrayOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_RATCHET).contains(encryptedEventContent.algorithm)) return null

val senderDevice = encryptedEventContent.deviceId
val recipients = if (cryptoConfig.limitRoomKeyRequestsToMyDevices) {
Expand Down Expand Up @@ -131,7 +132,7 @@ internal class OutgoingKeyRequestManager @Inject constructor(

private fun ratchetIndexForMessage(event: Event): Int? {
val encryptedContent = event.content.toModel<EncryptedEventContent>() ?: return null
if (encryptedContent.algorithm != MXCRYPTO_ALGORITHM_MEGOLM) return null
if (!arrayOf(MXCRYPTO_ALGORITHM_MEGOLM, MXCRYPTO_ALGORITHM_RATCHET).contains(encryptedContent.algorithm)) return null
return encryptedContent.ciphertext?.fromBase64()?.inputStream()?.reader()?.let {
tryOrNull {
val megolmVersion = it.read()
Expand Down Expand Up @@ -285,7 +286,6 @@ internal class OutgoingKeyRequestManager @Inject constructor(
// do we have known requests for that session??
Timber.tag(loggerTag.value).v("Cancel Key Request if needed for $sessionId")
val knownRequest = cryptoStore.getOutgoingRoomKeyRequest(
algorithm = MXCRYPTO_ALGORITHM_MEGOLM,
roomId = roomId,
sessionId = sessionId,
senderKey = senderKey
Expand Down
Loading