@@ -26,7 +26,6 @@ import org.sdn.android.sdk.api.logger.LoggerTag
2626import org.sdn.android.sdk.api.session.crypto.MXCryptoError
2727import org.sdn.android.sdk.api.session.crypto.model.CryptoDeviceInfo
2828import org.sdn.android.sdk.api.session.crypto.model.MXUsersDevicesMap
29- import org.sdn.android.sdk.api.session.crypto.model.UnknownInfo.sessionId
3029import org.sdn.android.sdk.api.session.crypto.model.forEach
3130import org.sdn.android.sdk.api.session.events.model.Content
3231import org.sdn.android.sdk.api.session.events.model.EventType
@@ -37,6 +36,7 @@ import org.sdn.android.sdk.api.session.room.model.message.MessageType
3736import org.sdn.android.sdk.internal.crypto.DeviceListManager
3837import org.sdn.android.sdk.internal.crypto.InboundGroupSessionHolder
3938import org.sdn.android.sdk.internal.crypto.MXOlmDevice
39+ import org.sdn.android.sdk.internal.crypto.MegolmSessionData
4040import org.sdn.android.sdk.internal.crypto.actions.EnsureOlmSessionsForDevicesAction
4141import org.sdn.android.sdk.internal.crypto.actions.MessageEncrypter
4242import org.sdn.android.sdk.internal.crypto.algorithms.IMXEncrypting
@@ -76,11 +76,11 @@ internal class MXRatchetEncryption(
7676 // OutboundSessionInfo. Null if we haven't yet started setting one up. Note
7777 // that even if this is non-null, it may not be ready for use (in which
7878 // case outboundSession.shareOperation will be non-null.)
79- private var currentSession : MXOutboundSessionInfo ? = null
79+ private var outboundSession : MXOutboundSessionInfo ? = null
8080
8181 init {
8282 // restore existing outbound session if any
83- currentSession = olmDevice.restoreOutboundGroupSessionForRoom(roomId)
83+ outboundSession = olmDevice.restoreOutboundGroupSessionForRoom(roomId)
8484 }
8585
8686 override suspend fun encryptEventContent (
@@ -138,7 +138,7 @@ internal class MXRatchetEncryption(
138138 }
139139
140140 override fun discardSessionKey () {
141- currentSession = null
141+ outboundSession = null
142142 olmDevice.discardOutboundGroupSessionForRoom(roomId)
143143 }
144144
@@ -185,6 +185,7 @@ internal class MXRatchetEncryption(
185185
186186 return MXOutboundSessionInfo (
187187 sessionId = sessionId,
188+ senderKey = olmDevice.deviceCurve25519Key!! ,
188189 sharedWithHelper = SharedWithHelper (roomId, sessionId, cryptoStore),
189190 clock = clock,
190191 sharedHistory = sharedHistory
@@ -198,28 +199,50 @@ internal class MXRatchetEncryption(
198199 */
199200 private suspend fun ensureCurrentSession (devicesInRoom : MXUsersDevicesMap <CryptoDeviceInfo >): MXOutboundSessionInfo {
200201 Timber .tag(loggerTag.value).v(" ensureCurrentSession roomId:$roomId " )
202+ val safeSession: MXOutboundSessionInfo
203+ val sharedHistory = cryptoStore.shouldShareHistory(roomId)
201204 val currentGroupSession = olmDevice.getCurrentGroupSession(roomId)
202205 val sessionId = currentGroupSession?.wrapper?.safeSessionId
203- val safeSession: MXOutboundSessionInfo
204- var needShare = true
205- if (sessionId != null ) {
206- val sharedHistory = cryptoStore.shouldShareHistory(roomId)
206+ val isNewSession: Boolean
207+ val exportedSession: MegolmSessionData ?
208+
209+ if (currentGroupSession != null && sessionId != null ) {
210+ Timber .tag(loggerTag.value).i(" ensureCurrentSession() : reuse existing session $sessionId in $roomId " )
207211 safeSession = MXOutboundSessionInfo (
208212 sessionId = sessionId,
213+ senderKey = currentGroupSession.wrapper.senderKey,
209214 sharedWithHelper = SharedWithHelper (roomId, sessionId, cryptoStore),
210215 clock = clock,
211216 sharedHistory = sharedHistory
212217 )
213- // if the session is not created by us then no need to share.
214- if (olmDevice.getSessionKey(sessionId) == null ) {
215- needShare = false
218+ isNewSession = false
219+ exportedSession = currentGroupSession.mutex.withLock {
220+ currentGroupSession.wrapper.exportKeys()
216221 }
217- } else {
218- safeSession = prepareNewSessionInRoom()
219- }
220222
221- if (! needShare) {
222- return safeSession
223+ } else {
224+ var session = outboundSession
225+ if (session == null ) {
226+ session = prepareNewSessionInRoom()
227+ outboundSession = session
228+ } else {
229+ olmDevice.addInboundGroupSession(
230+ sessionId = session.sessionId,
231+ sessionKey = olmDevice.getSessionKey(session.sessionId)!! ,
232+ roomId = roomId,
233+ algorithm = MXCRYPTO_ALGORITHM_RATCHET ,
234+ senderKey = olmDevice.deviceCurve25519Key!! ,
235+ forwardingCurve25519KeyChain = emptyList(),
236+ keysClaimed = mapOf (" ed25519" to olmDevice.deviceEd25519Key!! ),
237+ exportFormat = false ,
238+ sharedHistory = sharedHistory,
239+ trusted = true
240+ )
241+ }
242+ safeSession = session
243+ isNewSession = true
244+ exportedSession = null
245+ Timber .tag(loggerTag.value).i(" ensureCurrentSession() : use new session ${session.sessionId} in $roomId " )
223246 }
224247
225248 val shareMap = HashMap <String , MutableList <CryptoDeviceInfo >>()/* userId */
@@ -236,7 +259,18 @@ internal class MXRatchetEncryption(
236259 }
237260 val devicesCount = shareMap.entries.fold(0 ) { acc, new -> acc + new.value.size }
238261 Timber .tag(loggerTag.value).d(" roomId:$roomId found $devicesCount devices without megolm session(${safeSession.sessionId} )" )
239- shareKey(safeSession, shareMap)
262+
263+ // measure time consumed
264+ val ts = clock.epochMillis()
265+ if (isNewSession) {
266+ shareKey(safeSession, null , shareMap)
267+ } else {
268+ // offload to io thread
269+ cryptoCoroutineScope.launch(coroutineDispatchers.io) {
270+ shareKey(safeSession, exportedSession, shareMap)
271+ }
272+ }
273+ Timber .tag(loggerTag.value).d(" shareKey in $roomId done in ${clock.epochMillis() - ts} millis" )
240274 return safeSession
241275 }
242276
@@ -248,6 +282,7 @@ internal class MXRatchetEncryption(
248282 */
249283 private suspend fun shareKey (
250284 session : MXOutboundSessionInfo ,
285+ export : MegolmSessionData ? ,
251286 devicesByUsers : Map <String , List <CryptoDeviceInfo >>
252287 ) {
253288 // nothing to send, the task is done
@@ -265,10 +300,11 @@ internal class MXRatchetEncryption(
265300 break
266301 }
267302 }
303+
268304 Timber .tag(loggerTag.value).v(" shareKey() ; sessionId<${session.sessionId} > userId ${subMap.keys} " )
269- shareUserDevicesKey(session, subMap)
305+ shareUserDevicesKey(session, export, subMap)
270306 val remainingDevices = devicesByUsers - subMap.keys
271- shareKey(session, remainingDevices)
307+ shareKey(session, export, remainingDevices)
272308 }
273309
274310 /* *
@@ -279,24 +315,32 @@ internal class MXRatchetEncryption(
279315 */
280316 private suspend fun shareUserDevicesKey (
281317 sessionInfo : MXOutboundSessionInfo ,
318+ exportedSessionData : MegolmSessionData ? ,
282319 devicesByUser : Map <String , List <CryptoDeviceInfo >>
283320 ) {
284- val sessionKey = olmDevice.getSessionKey(sessionInfo.sessionId) ? : return Unit .also {
285- Timber .tag(loggerTag.value).v(" shareUserDevicesKey() Failed to share session, failed to export" )
286- }
287321 val chainIndex = olmDevice.getMessageIndex(sessionInfo.sessionId)
288322
289- val payload = mapOf (
290- " type" to EventType .ROOM_KEY ,
291- " content" to mapOf (
292- " algorithm" to MXCRYPTO_ALGORITHM_RATCHET ,
293- " room_id" to roomId,
294- " session_id" to sessionInfo.sessionId,
295- " session_key" to sessionKey,
296- " chain_index" to chainIndex,
297- " org.matrix.msc3061.shared_history" to sessionInfo.sharedHistory
323+ val payload = if (exportedSessionData != null ) {
324+ mapOf (
325+ " type" to EventType .FORWARDED_ROOM_KEY ,
326+ " content" to exportedSessionData
298327 )
299- )
328+ } else {
329+ val sessionKey = olmDevice.getSessionKey(sessionInfo.sessionId) ? : return Unit .also {
330+ Timber .tag(loggerTag.value).e(" shareUserDevicesKey() Failed to share session, failed to export" )
331+ }
332+ mapOf (
333+ " type" to EventType .ROOM_KEY ,
334+ " content" to mapOf (
335+ " algorithm" to MXCRYPTO_ALGORITHM_RATCHET ,
336+ " room_id" to roomId,
337+ " session_id" to sessionInfo.sessionId,
338+ " session_key" to sessionKey,
339+ " chain_index" to chainIndex,
340+ " org.matrix.msc3061.shared_history" to sessionInfo.sharedHistory
341+ )
342+ )
343+ }
300344
301345 var t0 = clock.epochMillis()
302346 Timber .tag(loggerTag.value).v(" shareUserDevicesKey() : starts" )
@@ -421,7 +465,7 @@ internal class MXRatchetEncryption(
421465 payloadJson[" type" ] = eventType
422466 payloadJson[" content" ] = eventContent
423467
424- val sessionWrapper = olmDevice.getCurrentGroupSession(roomId)?.wrapper ? : throw Exception ( " no current session for room: $ roomId" )
468+ val sessionWrapper = olmDevice.getInboundGroupSession(session.sessionId, session.senderKey, roomId).wrapper
425469 val currentSession = sessionWrapper.session
426470 if (currentSession.sessionIdentifier() != session.sessionId) {
427471 throw Exception (" current session $session .sessionId is invalid for room: $roomId " )
0 commit comments