You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

End-to-End Encryption using Insertable Streams

Overview

NOTE e2ee is work in progress.

This document describes some of the high-level concepts and outlines the design. Please refer to the source code for details.

This library implements End-to-End Encryiption (E2EE) on supported endpopints (currently just browsers with support for insertable streams).

This implementation follows the model outlined in SFrame with slight changes.

Signaling

Each participant will have a randomly generated key which is used to encrypt the media. The key is distributed with other participants (so they can decrypt the media) via an E2EE channel which is established with Olm.

Key rotation

Each participant’s key is rotated (a new random one is generated) every time a participant leaves. This new key is then sent to every other participant over the E2EE Olm channel.

Key ratcheting

Each participant ratchets their key when another participant joins. The new resulting key is not distributed since every participant can derive it by ratchetting themselves.

Unlike described in SFrame 4.3.5.1 we attempt to ratchet the key forward when we do not find a valid authentication tag. Note that we only update the set of keys when we find a valid signature which avoids a denial of service attack with invalid signatures.

Media

Packet format

We are using a variant of SFrame that uses a trailer instead of a header. We call it JFrame.

At a high level the encrypted frame format looks like this:

     +------------+------------------------------------------+^+
     |unencrypted payload header (variable length)           | |
   +^+------------+------------------------------------------+ |
   | |                                                       | |
   | |                                                       | |
   | |                                                       | |
   | |                                                       | |
   | |                  Encrypted Frame                      | |
   | |                                                       | |
   | |                                                       | |
   | |                                                       | |
   | |                                                       | |
   +^+-------------------------------------------------------+ +
   | |                 Authentication Tag                    | |
   | +---------------------------------------+-+-+-+-+-+-+-+-+ |
   | |    CTR... (length=LEN + 1)            |R|LEN  |KID    | |
   | +---------------------------------------+-+-+-+-+-+-+-+-+^|
   |                                                           |
   +----+Encrypted Portion            Authenticated Portion+---+

We do not encrypt the first few bytes of the packet that form the VP8 payload (10 bytes for key frames, 3 bytes for interframes) nor the Opus TOC byte.

This allows the decoder to understand the frame a bit more and makes it decode the fun looking garbage we see in the video. This also means the SFU does not know (ideally) that the content is end-to-end encrypted and there are no changes in the SFU required at all.

Using Web Workers

Insertable Streams are transferable and can be sent from the main JavaScript context to a Web Worker. We are using a named worker (E2EEworker) which allows very easy inspection in Chrome DevTools.