End-to-end encryption (Beta)
Updated
Implement end-to-end encryption to ensure data security during transmission.
Supported platform: Web.
To enhance data security, Agora provides media stream encryption and end-to-end encryption. End-to-end encryption encrypts the media stream on the sending device and decrypts it on the receiving device, ensuring that third parties cannot access the data during transmission.
The end-to-end encryption is based on the WebRTC Encoded Transform standard. However, since WebRTC Encoded Transform is still maturing and may have compatibility or performance issues, there are some restrictions on its use:
- Only VP8 video and Opus audio are supported.
- It supports publishing and receiving audio and video streams between Web clients only, with no cross-platform compatibility or bypass streaming services.
- The SEI information transmission feature cannot be enabled due to conflicts with browser components.
Understand the tech
The end-to-end encryption technology is based on the following key concepts:
- WebRTC Encoded Transform: A technology for encoding transformations in WebRTC. It provides a read and write interface for encoded WebRTC data, enabling developers to convert encoding formats, adjust bit rates, or apply filters.
- WebRTC Encoded Transform processing pipeline: A sequence of operations used to process WebRTC encoded data.
- RTCRtpSender and RTCRtpReceiver: Standard WebRTC components.
RTCRtpSenderhandles sending encoded data, whileRTCRtpReceiveris responsible for receiving it. Together, they form the WebRTC Encoded Transform processing pipeline. - RTCRtpTransceiver: A WebRTC API for managing both audio and video streams.
RTCRtpSenderandRTCRtpReceiverare accessible through the.senderand.receiverproperties of theRTCRtpTransceiverobject.
For each audio or video track, the Web SDK offers the getRTCRtpTransceiver method to retrieve the RTCRtpTransceiver. After obtaining RTCRtpSender and RTCRtpReceiver from RTCRtpTransceiver, set up the WebRTC Encoded Transform processing pipeline to encrypt and decrypt audio or video data.
Prerequisites
- Ensure that you have implemented the SDK quickstart in your project.
- A supported browser:
- Chrome (desktop and mobile): version 87 or later
- Safari (desktop and mobile): version 15.4 or later
- Contact support@agora.io to enable end-to-end encryption.
Implement end-to-end encryption
This section shows you how to implement video encryption on the sender side and decryption on the receiver side using Chrome as an example. The steps for Safari are slightly different.
The example uses the AES encryption algorithm from the Web Crypto API. To implement a custom encryption and decryption algorithm, use WebAssembly.
-
Publish the encrypted media stream
To establish a WebRTC Encoded Transform processing pipeline on the publishing end:
-
After publishing the local video track, call the
getRTCRtpTransceivermethod provided by the SDK to obtain the local video track'sRTCRtpTransceiverinstance. Then, retrieve theRTCRtpSenderinstance through thesenderproperty. -
Use the browser's native Streams API to encrypt the video stream.
Refer to the following sample code:
async function publish() { // Publish the local video track await client.publish([localVideoTrack]); // Get the RTCRtpTransceiver instance for the local video track const transceiver = localVideoTrack.getRTCRtpTransceiver(); if (!transceiver || !transceiver.sender) { return; } // Get the RTCRtpSender to control the media data being sent const sender = transceiver.sender; // Define the encryption method for the Chrome browser if (isChrome) { // Create an encoded stream for encryption transformation const streams = sender.createEncodedStreams(); // Create the encryption transformer const transformer = new TransformStream({ transform(chunk, controller) { // The first 7 bytes of VP8 video key frames and the first 3 bytes of non-key frames need to be preserved and not encrypted; otherwise, media transmission will fail const vp8ReservedSize = chunk.type === 'key' ? 7 : 3; // Implement the encrypt method yourself according to your encryption requirements // The example uses the AES encryption algorithm provided by the Web Crypto API const encryptedChunk = encrypt(chunk, key, vp8ReservedSize); controller.enqueue(encryptedChunk); }, }); // Connect the encoded stream and the encryption transformer and write the result to the data stream streams.readable.pipeThrough(transformer).pipeTo(streams.writable); } } -
-
Subscribe to the encrypted media stream
To establish the WebRTC Encoded Transform processing pipeline on the receiving end:
-
When subscribing to a remote video stream, call the
getRTCRtpTransceivermethod provided by the SDK to obtain an instance of the remote video track'sRTCRtpTransceiver. -
Call the browser's native Streams API to decrypt the video stream.
Refer to the following sample code:
async function subscribe(user, mediaType) { // Get the RTCRtpTransceiver instance of the remote video track const transceiver = user.videoTrack.getRTCRtpTransceiver(); if (!transceiver || !transceiver.receiver) { return; } // Get the RTCRtpReceiver to control the received media data const receiver = transceiver.receiver; // Define the decryption method for Chrome browser if (isChrome) { // Create an encoded stream for decryption const streams = receiver.createEncodedStreams(); // Create a decryption transformer const transformer = new TransformStream({ transform(chunk, controller) { // The first 7 bytes of VP8 video keyframes and the first 3 bytes of non-keyframes do not need decryption const vp8ReservedSize = chunk.type === 'key' ? 7 : 3; // Implement the decrypt method yourself according to your decryption requirements const decryptedChunk = decrypt(chunk, key, vp8ReservedSize); controller.enqueue(decryptedChunk); }, }); // Connect the encoded stream and the decryption transformer, and write the results to the data stream streams.readable.pipeThrough(transformer).pipeTo(streams.writable); } } -
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects of this product.
Development considerations
If the SDK disconnects and then reconnects, the RTCRtpTransceiver instance corresponding to the current track may change. Obtain the new RTCRtpTransceiver object through the following callbacks:
- Local track:
transceiver-updated - Remote track:
transceiver-updated
After enabling end-to-end encryption, browser restrictions require creating an empty encryption pipeline for local tracks created using the Web SDK, even if encryption isn't needed. Without this, media data cannot be sent. Use the following code to create the empty encryption pipeline:
async function publish() {
// Publish the local video track
await client.publish([localVideoTrack]);
// Get the RTCRtpTransceiver instance of the local video track
const transceiver = localVideoTrack.getRTCRtpTransceiver();
if (!transceiver || !transceiver.sender) {
return;
}
// Get the RTCRtpSender to control the media being sent
const sender = transceiver.sender;
// Define the encryption mechanism for Chrome
if (isChrome) {
// Create encoded streams for transformation
const streams = sender.createEncodedStreams();
// Create a transform stream for handling the data
const transformer = new TransformStream({
transform(chunk, controller) {
// Directly write back the data
controller.enqueue(chunk);
},
});
// Pipe the encoded stream through the transformer and write it to the data stream
streams.readable.pipeThrough(transformer).pipeTo(streams.writable);
}
}API reference
- Provided by the Web SDK
- Browser Native Streams API
