New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for PERC Lite streams #933

Open
wants to merge 56 commits into
base: master
from

Conversation

Projects
None yet
3 participants
@lminiero
Member

lminiero commented Jun 27, 2017

Just as the VP9 SVC effort, this PR is the result of another collaboration with @agouaillard and @murillo128 (again, more details will be provided in a blog post we'll post later) and implements support for PERC Lite streams in Janus.

In case you have no idea what I'm talking about, PERC (Privacy Enhanced RTP Conferencing) is an ongoing standardization effort at the IETF, that's aimed (in layman's words) at providing end-to-end encryption even when streams go through a WebRTC server. This means that the WebRTC server (Janus in this case) has no access to the media streams, which are encrypted but can still relay them. This is particularly useful in scenarios where privacy and confidentiality are important (no one but the participants should be able to get the media), and still benefit from the features SFUs can provide when compared to P2P meshes. The implementation you find here is the one for the so called "PERC Lite" proposal, which is basically a double encryption: you can learn more about it in this thread, which contains slides and a document describing how it works.

Prerequisites for playing with this

Notice that to test this you'll need a PERC-compliant browser. Regular browsers will not generate PERC streams, and so will do nothing. You can find the code for a patched version of Chromium that supports PERC Lite here.

Testing in Janus

The way it's integrated in Janus is pretty simple. When you create a handle, you tell Janus whether it's going to be for PERC PeerConnections or not. This is only needed because Janus needs to know whether media packets will be encrypted or not: in fact, plugins like the AudioBridge need to be able to decode and encode media packets themselves, something that would not be possible with a double encrypted stream like PERC implements. Besides, recordings are affected as well (more on that later), which means we need to mark them as PERC recordings in case. To tell Janus the handle will be for PERC streams, with janus.js you just pass a percLite: true when attaching, e.g.:

	janus.attach(
		{
			plugin: "janus.plugin.videoroom",
			opaqueId: opaqueId,
			percLite: true,
			[...]

This basically means the attach request will contain a perc: true attribute (in case you're talking the Janus API directly, and not via janus.js). Once done that, you'll need to provide the encryption key before do any createOffer or createAnswer. The key must be 44 bytes and Base64 encoded, e.g.:

	var key = "12345678901234567890123456789012345678901234";
	var percKey = btoa(key);
	sfutest.setPercKey(percKey);

This transparently results in an additional configuration property set when creating the PeerConnection, that is mediaCryptoKey: percKey (you can check the janus.js changes for more details).

Keys and participants

Since this is for end-to-end encryption, you'll need to make sure that all the parties in the communication use the same key. For instance, for a PERC VideoRoom, all users joining the same room will need to use the same key, or they won't be able to talk to each other. The encryption is done in JavaScript as it needs to happen on the PeerConnection object: this means that Janus (or anybody not meant to) must NOT have access to the key, or the purpose of PERC would be pointless.

The patch comes with a pre-configured VideoRoom for PERC usage (room 3456) and with a dedicated demo page to test how it works (perctest.html). This patch has been also tested successfully with other plugins (EchoTest, Record&Play), and should work with a few others. Some plugins will explicitly reject PERC instead (SIP, AudioBridge, VoiceMail), due to what they need to be able to do to work.

Recordings

As I was anticipating, recordings are affected as well. In fact, if streams are encrypted twice, Janus can only unencrypt the hop-by-hop encryption, the usual WebRTC secure connection. The media itself, though, is not a stream of media packets, but another layer of encryption. This means that our MJR recordings are useless as they are, as while the janus-pp-rec postprocessor can still extract the payload from RTP packets and dump them to a media file, the media file would be unplayable. In order to fix this, we explicitly mark MJR files are PERC, when they were originated from a PERC stream, so that we can handle them accordingly.

For the Record&Play demo this is not a problem, if you use the right key when doing a playout. In fact, the idea is that you'll use a specific key when recording, which means the MJR files will contain RTP packets that are end-to-end encrypted using that key. If you want to play that out, you'll need to setup a PeerConnection that uses the same key that was used for recording, which will allow the browser to decrypt the stream and watch it (à-la DRM, if you like). Using the wrong key, or no key at all, will prevent the viewer to play the recording out.

When the purpose is processing those recording to a media file, though, the only way to get something meaningful from those MJR files is passing them to a new tool we created for the purpose, called janus-pp-unperc. As the name suggests, this tool unencrypts the second encryption layer too, and generates a plain MJR file that can be passed to janus-pp-rec for processing. Of course, this only works if janus-pp-unperc has access to the key that was used to encrypt end-to-end (the one you used above in JavaScript), which means you'll have to pass it via command line:

	./janus-pp-unperc key source.mjr destination.mjr

e.g.:

	./janus-pp-unperc MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ= perc-recording.mjr plain-recording.mjr

If you don't have access to the key (and Janus won't give it to you as it doesn't know it), then the file is pretty much useless.

That's all, folks

Feedback welcome!

@chadfurman

This comment has been minimized.

Contributor

chadfurman commented Aug 6, 2017

@lminiero This is super ultra exciting! Any news on when this will be mainline in chrome?

@chadfurman

This comment has been minimized.

Contributor

chadfurman commented Aug 6, 2017

@lminiero there's also ultra minor merge conflicts between this and the refcount branch.

@chadfurman

This comment has been minimized.

Contributor

chadfurman commented Aug 21, 2017

Not sure how to get the patched version of chromium working. Looks like it's quite different than the chromium trunk here: https://github.com/chromium/chromium/tree/trunk and no "forked from" references.

There's also no Makefile, nore is there a configure.ac and so I'm not sure what to do with https://github.com/agouaillard/perc-webrtc

@chadfurman

This comment has been minimized.

Contributor

chadfurman commented Aug 21, 2017

@agouaillard

This comment has been minimized.

agouaillard commented Aug 23, 2017

@chadfurman

This comment has been minimized.

Contributor

chadfurman commented Aug 24, 2017

Perfect! Thank you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment