E2EE encryption issues during setMediaEncryptionKey

I have used an example from a meet react sdk.

And modified in a next way handleApiReady

const handleApiReady = apiObj => {
        apiRef.current = apiObj;
        apiRef.current.on('knockingParticipant', handleKnockingParticipant);
        apiRef.current.on('audioMuteStatusChanged', payload => handleAudioStatusChange(payload, 'audio'));
        apiRef.current.on('videoMuteStatusChanged', payload => handleAudioStatusChange(payload, 'video'));
        apiRef.current.on('raiseHandUpdated', printEventOutput);
        apiRef.current.on('titleViewChanged', printEventOutput);
        apiRef.current.on('chatUpdated', handleChatUpdates);
        apiRef.current.on('knockingParticipant', handleKnockingParticipant);


        apiObj.on("videoConferenceJoined", async (event) => {
            let secretKey = new Uint8Array(32);
            console.log("Logger ApiObj", apiObj);

            let index = 0;
            let key = await window.crypto.subtle.importKey(
                "raw",
                secretKey,
                "AES-GCM",
                true,
                ["encrypt", "decrypt"]
            );

            console.log("Logger Key", key);
            await apiObj.setMediaEncryptionKey({
                key,
                index
            }).then(() => {
                console.log("SET MEDIA ENCRYPTION KEY");
                apiObj.toggleE2EE(true);
            });

            console.log("Logger Jitsi Meet External API", await apiObj.isStartSilent());
            apiObj.toggleE2EE(true);
        })
    };

Also, modified JitsiMeeting element. Added a configOverwrite.

configOverwrite={{
     e2ee: {
         externallyManagedKey: true
     }
}}

But receive an error.

Logger.js:154 2022-12-03T20:06:37.883Z [modules/xmpp/strophe.jingle.js] <na.onJingle>: invalid session id: d89ph85do4u7e

Did you toggle e2ee on first?

Please take a look above at a code example that I shared.

I have tried different combinations with placing a toggleE2EE and setMediaEncryptionKey but it doesn’t work.
It works if the green lock doesn’t appear and the voice doesn’t say “End-to-end encryption enabled”.

Oh I hadn’t realized the code sample had scroll…

Hum. In principle you should be able to toggle it, then set the key. Does it work if you add a small delay between the 2 operations?

I have tried to add delays in a next way =>
Sometimes it works, but it’s very rare. Most of the time I have the same error. createEncodedStreams

apiObj.on("videoConferenceJoined", async (event) => {
            let secretKey = new Uint8Array(32);

            let index = 0;
            let key = await window.crypto.subtle.importKey(
                "raw",
                secretKey,
                "AES-GCM",
                true,
                ["encrypt", "decrypt"]
            );

            console.log("Logger Key", key);
            apiObj.toggleE2EE(true);
            setTimeout(() => {
                apiObj.setMediaEncryptionKey({
                    key,
                    index
                 }).then(() => {
                    console.log("SET MEDIA ENCRYPTION KEY");
                  });
            }, 1000);
})

This approach doesn’t enable e2ee.

apiObj.on("videoConferenceJoined", async (event) => {
            let secretKey = new Uint8Array(32);

            let index = 0;
            let key = await window.crypto.subtle.importKey(
                "raw",
                secretKey,
                "AES-GCM",
                true,
                ["encrypt", "decrypt"]
            );

            await apiObj.setMediaEncryptionKey({
                key,
                index
            }).then(() => {
                console.log("SET MEDIA ENCRYPTION KEY");
            });

            setTimeout(() => {
                apiObj.toggleE2EE(true);
            }, 1000);
})

What server are you testing with?

You may need more than 1 second since the media session need to be re-established. I think option 1 with more delay is a good candidate, but we should handle this better: setting a key like that should turn it on…

I have increased the timeout to 5 secs, but I still, have an error:

Logger.js:154 2022-12-05T15:39:37.355Z [JitsiMeetJS.ts] <Object.getGlobalOnErrorHandler>:  UnhandledError: Strophe: Error: Failed to execute 'createEncodedStreams' on 'RTCRtpSender': Encoded audio streams not requested at PC initialization

I guess I am using the main server. I am using an example from a meet-react-sdk.

Interesting, I just moved toggleE2EE into timeout func too and the error disappeared. But I don’t receive any video or audio.

setTimeout(() => {
     apiObj.toggleE2EE(true);
     apiObj.setMediaEncryptionKey({
          key,
          index
      }).then(() => {
          console.log("SET MEDIA ENCRYPTION KEY");
      });
}, 1000);

Here is the logs, after e2ee is enabled:


App.jsx:132 SET MEDIA ENCRYPTION KEY
Logger.js:154 2022-12-05T15:50:08.291Z [modules/API/API.js] <toggle-e2ee>:  Toggle E2EE key command received
Logger.js:154 2022-12-05T15:50:08.291Z [features/e2ee] E2EE will be enabled
Logger.js:154 2022-12-05T15:50:08.292Z [modules/xmpp/JingleSessionPC.js] <Zo.terminate>:  JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] Sending session-terminate
Logger.js:154 2022-12-05T15:50:08.292Z [modules/xmpp/JingleSessionPC.js] <Zo.terminate>:  <iq to=​"uehjdb%3edhufb37fgs3@conference.meet.jit.si/​focus" type=​"set" xmlns=​"jabber:​client" id=​"35381561-b9a6-4a26-b3ea-823e5f476375:​sendIQ">​…​</iq>​
Logger.js:154 2022-12-05T15:50:08.292Z [modules/xmpp/JingleSessionPC.js] <Zo.onTerminated>:  JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] Session terminated undefined undefined
Logger.js:154 2022-12-05T15:50:08.292Z [modules/xmpp/JingleSessionPC.js] <Zo.close>:  JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] Clearing modificationQueue
Logger.js:154 2022-12-05T15:50:08.293Z [modules/xmpp/JingleSessionPC.js] <Zo.close>:  JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] Queued PC close task
Logger.js:154 2022-12-05T15:50:08.293Z [modules/xmpp/JingleSessionPC.js] <Zo.close>:  JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] Shutdown modificationQueue!
Logger.js:154 2022-12-05T15:50:08.293Z [JitsiConference.js] <Gu._maybeStartOrStopP2P>:  Auto P2P disabled
Logger.js:154 2022-12-05T15:50:08.312Z [modules/connectivity/TrackStreamingStatus.ts] <kd.figureOutStreamingStatus>:  Figure out conn status for c6387bb7-v0, is video muted: false video track frozen: false p2p mode: false is in forwarded sources: true currentStatus => newStatus: active => active
Logger.js:154 2022-12-05T15:50:08.315Z [modules/RTC/JitsiRemoteTrack.js] <Bd._removeEventListener>:  Disposing track streaming status: c6387bb7-v0
Logger.js:154 2022-12-05T15:50:08.322Z [modules/RTC/JitsiRemoteTrack.js] <Bd._removeEventListener>:  Disposing track streaming status: c6387bb7-v0
Logger.js:154 2022-12-05T15:50:08.326Z [modules/RTC/TraceablePeerConnection.js] <Wd.close>:  TPC[id=1,type=JVB] Closing peerconnection
Logger.js:154 2022-12-05T15:50:08.336Z [modules/xmpp/JingleSessionPC.js] JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0] PC close task done!
Logger.js:154 2022-12-05T15:50:08.336Z [modules/UI/videolayout/LargeVideoManager.js] Scheduled large video update for c6387bb7
Logger.js:154 2022-12-05T15:50:08.337Z [modules/RTC/JitsiRemoteTrack.js] <Bd._removeEventListener>:  Disposing track streaming status: c6387bb7-v0
Logger.js:154 2022-12-05T15:50:08.350Z [modules/RTC/JitsiRemoteTrack.js] <MediaStreamTrack.<anonymous>>:  "onended" event(1670255408350): RemoteTrack[userID: c6387bb7, type: audio, ssrc: 3964143995, p2p: false, sourceName: c6387bb7-a0, status: {readyState: ended, muted: false, enabled: true}]
Logger.js:154 2022-12-05T15:50:08.351Z [modules/RTC/JitsiRemoteTrack.js] <MediaStreamTrack.<anonymous>>:  "onended" event(1670255408350): RemoteTrack[userID: c6387bb7, type: video, ssrc: 1257382726, p2p: false, sourceName: c6387bb7-v0, status: {readyState: ended, muted: true, enabled: true}]
Logger.js:154 2022-12-05T15:50:08.650Z [modules/UI/videolayout/LargeVideoManager.js] Scheduled large video update for c6387bb7
Logger.js:154 2022-12-05T15:50:11.615Z [modules/RTC/BridgeChannel.js] <e.onmessage>:  Endpoint connection status changed: db58ff9e active=false
Logger.js:154 2022-12-05T15:50:18.371Z [JitsiConference.js] <jvbJingleSession.jvbJingleSession.terminate.reason>:  An error occurred while trying to terminate the JVB session {reason: 'timeout', session: 'JingleSessionPC[session=JVB,initiator=false,sid=8talrf0sgnau0]'}
r @ Logger.js:154
jvbJingleSession.jvbJingleSession.terminate.reason @ JitsiConference.js:3844
(anonymous) @ JingleSessionPC.js:2962
(anonymous) @ strophe.umd.js:2732
run @ strophe.umd.js:1938
_onIdle @ strophe.umd.js:3869
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
setTimeout (async)
_onIdle @ strophe.umd.js:3885
(anonymous) @ strophe.umd.js:3886
Logger.js:154 2022-12-05T15:50:48.896Z [modules/statistics/AudioOutputProblemDetector.js] A potential problem is detected with the audio output for participant c6387bb7, local audio levels: [null,null], remote audio levels: undefined
r @ Logger.js:154
(anonymous) @ AudioOutputProblemDetector.js:122
_onLocalAudioLevelsReport @ AudioOutputProblemDetector.js:111
r.emit @ events.js:158
yi._processAndEmitReport @ RTPStatsCollector.js:400
yi.processStatsReport @ RTPStatsCollector.js:677
(anonymous) @ RTPStatsCollector.js:247
Promise.then (async)
t @ RTPStatsCollector.js:241
setInterval (async)
yi.start @ RTPStatsCollector.js:258
Ri.startRemoteStats @ statistics.js:233
Gu._acceptJvbIncomingCall @ JitsiConference.js:2293
Gu.onIncomingCall @ JitsiConference.js:2204
r.emit @ events.js:153
onJingle @ strophe.jingle.js:217
run @ strophe.umd.js:1875
(anonymous) @ strophe.umd.js:3157
forEachChild @ strophe.umd.js:830
_dataRecv @ strophe.umd.js:3146
_onMessage @ strophe.umd.js:5836
Logger.js:154 2022-12-05T15:51:54.964Z [modules/xmpp/XmppConnection.js] <Xs._maybeStartWSKeepAlive>:  Scheduling next WebSocket keep-alive in 62164.68407556312ms
Logger.js:154 2022-12-05T15:51:58.457Z [modules/RTC/BridgeChannel.js] <e.onclose>:  Channel closed by server

localhost-1670255909336.log (140.8 KB)

You ran into an issue I also into this morning. The latest deployment seems to have broken session restarts, and this is required for E2EE to work.

I have fixed this in master and the next release won’t give that error, which prevents the session from getting established after E2EE is turned on.

Could you please point me, to where I could monitor the next release?

I watch this repo to keep in touch with updates – GitHub - jitsi/jitsi-meet-release-notes: Release notes for Jitsi Meet: the web frontend, mobile apps and mobile SDKs

@saghul Could you please give me any updates regarding this issue?

The latest stable release (made yesterday) fixed the session restart, so can you please give this a try again?

I just tested with the latest @jitsi/react-sdk - npm and seems like everything works as before. Maybe I should update something on my side?

@saghul

Sorry, I meant we updated the server side, the Jitsi Meet deployment. Since the React SDK loads the meeting using an iframe updating the server is enough.

Do you have any suspects why it could still not work properly?

Have you updated your deployment to the latest stable? If not you don’t have the media restart fix.

Sorry for confusing you. I will explain more about how I am using a Jitsi react SDK. I have cloned an example, then modified it to start in the same meeting room each time I serve an application. Then, open two tabs in the browser, enter different names, and press start meeting. Basically, that is the whole flow.

By the way, I have managed to establish a successful call with e2ee and custom keys.

// onApiReady

let key = await window.crypto.subtle.importKey(
        "raw",
        secretKey,
        "AES-GCM",
        true,
        ["encrypt", "decrypt"]
);

await externalApi.setMediaEncryptionKey({
    key,
    index
});

setTimeout(() => {
    externalApi.toggleE2EE(true);
}, 1_000);

I don’t know if it’s the right way, but it’s working.
If I change it to opposite calls between toggle and setMediaEncryptionKey it stops working.

It makes sense that it works that way indeed.

What confused me is the fact that you hadn’t mentioned what server you are connecting to. meet.jit.si uses the automatic mode so it must be a different one, and then you still needed that fix so the media session could be re-created.

1 Like