How to use secure RTP in Wowza Streaming Engine

Wowza Streaming Engine supports Secure Real-time Transport Protocol (secure RTP or SRTP) for media publishing and playback. The encryption keys can be passed either in the SDP data (RTSP SDP exchange or SDP file) or through the Java API. The open source tools ffmpeg and ffplay can be used for SRTP testing.

Notes:
  • Wowza Streaming Engine™ 4.3.0 or later is required.
     
  • Advanced knowledge of Java and cryptography is required to use this article.

SRTP for Publishing

The open source tool ffmpeg can be used to publish an SRTP stream to Wowza Streaming Engine. In this case, the crypto keys are passed in the SDP data. The following is an example command line (using ffmpeg) for re-publishing the video track of sample.mp4 as a live stream:
ffmpeg -re -i sample.mp4 -an -vcodec copy -f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params "NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj" "srtp://localhost:10000"
You'll see the SDP information in the tool's console output. It should look something like this:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=Big Buck Bunny, Sunflower version
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 56.26.101
m=video 10000 RTP/AVP 96
b=AS:640
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0LAFdoCAJbARAAAAwAEAAADAPA8WLqA,aM4yyA==; profile-level-id=42C015
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj
Copy this information and paste into an SDP (.sdp) file, and then place the file in the Wowza Streaming Engine content folder ([install-dir]/content). Then use Wowza Streaming Engine Manager to start this SDP file. You should see the stream being properly published to Wowza Streaming Engine. In this case, the crypto information is in the SDP data. The following line includes the crypto key used for decryption:
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj
Other use cases might demand this data to be handled outside the SDP data. In this case, there's a Java API for intercepting incoming RTP sessions and injecting the crypto information. The following is an example of a module that injects this same key information through the Java API:
import java.security.*;
import java.util.*;

import com.wowza.util.*;
import com.wowza.wms.module.*;
import com.wowza.wms.rtp.model.*;
import com.wowza.wms.util.*;

public class ModuleSRTPPlaybackTest extends ModuleBase
{
	private MyRTPEncryptionProvider encryptionProvider = new MyRTPEncryptionProvider();
	private Random rnd = new SecureRandom();

	class MyRTPEncryptionProvider implements IRTPEncryptionProvider
	{
		public void onTrack(RTPSession rtpSession, RTPTrack rtpTrack)
		{
			while(true)
			{
				RTPStream rtpStream = rtpSession.getRTSPStream();
				if (rtpStream == null)
				{
					getLogger().warn("ModuleSRTPPlaybackTest.onRTPSessionCreate: No RTPStream");
					break;
				}

				byte[] keyBytes = new byte[SRTPUtils.KEY_CIPHER_BITLEN/8];
				byte[] saltBytes = new byte[SRTPUtils.KEY_SALT_BITLEN/8];

				byte[] cryptoBytes = Base64.decode("NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj");

				System.arraycopy(cryptoBytes, 0, keyBytes, 0, keyBytes.length);
				System.arraycopy(cryptoBytes, keyBytes.length, saltBytes, 0, saltBytes.length);

				int mkiLen = 0;
				long mki = SRTPKeyContext.MKI_NONE;
				int cryptoType = SRTPUtils.SRTP_AES128_CM_HMAC_SHA1_80_ID;
				int keyDerivationRate = 0;

				int encMethod = SRTPUtils.cryptoTypeToEncMethod(cryptoType);
				int authMethod = SRTPUtils.cryptoTypeToAuthMethod(cryptoType);
				int authLen = SRTPUtils.cryptoTypeToAuthLen(cryptoType);

				SRTPKeyContext srtpKeyContext = new SRTPKeyContext(encMethod, authMethod, authLen);
				SRTPMasterKey srtpMasterKey = new SRTPMasterKey(keyBytes, saltBytes);

				srtpKeyContext.setMKILen(mkiLen);
				srtpKeyContext.putMasterKey(mki, srtpMasterKey);
				srtpKeyContext.setKeyDerivationRate(keyDerivationRate);

				getLogger().warn("ModuleSRTPPlaybackTest.onRTPSessionCreate: Set encryption info ["+rtpTrack.getTrackId()+"]: keyBytes:"+BufferUtils.encodeHexString(keyBytes)+" saltBytes:"+BufferUtils.encodeHexString(saltBytes));

				rtpTrack.setSRTPKeyContextIn(srtpKeyContext);
				break;
			}
		}
	}

	public void onRTPSessionCreate(RTPSession rtpSession)
	{
		getLogger().info("ModuleSRTPPlaybackTest.onRTPSessionCreate");

		rtpSession.setEncryptionProvider(encryptionProvider);

	}
}

SRTP for playback

For playback, the crypto keys must be provided through the Java API. The following is an example of a module that sets random key data for all RTP sessions:
import java.security.*;
import java.util.*;

import com.wowza.util.*;
import com.wowza.wms.module.*;
import com.wowza.wms.rtp.model.*;
import com.wowza.wms.util.*;

public class ModuleSRTPPlaybackTest extends ModuleBase
{
	private MyRTPEncryptionProvider encryptionProvider = new MyRTPEncryptionProvider();
	private Random rnd = new SecureRandom();

	class MyRTPEncryptionProvider implements IRTPEncryptionProvider
	{
		public void onTrack(RTPSession rtpSession, RTPTrack rtpTrack)
		{
			while(true)
			{
				RTPStream rtpStream = rtpSession.getRTSPStream();
				if (rtpStream == null)
				{
					getLogger().warn("ModuleSRTPPlaybackTest.onRTPSessionCreate: No RTPStream");
					break;
				}

				byte[] keyBytes = new byte[SRTPUtils.KEY_CIPHER_BITLEN/8];
				byte[] saltBytes = new byte[SRTPUtils.KEY_SALT_BITLEN/8];

				rnd.nextBytes(keyBytes);
				rnd.nextBytes(saltBytes);

				int mkiLen = 0;
				long mki = SRTPKeyContext.MKI_NONE;
				int cryptoType = SRTPUtils.SRTP_AES128_CM_HMAC_SHA1_80_ID;
				int keyDerivationRate = 0;

				int encMethod = SRTPUtils.cryptoTypeToEncMethod(cryptoType);
				int authMethod = SRTPUtils.cryptoTypeToAuthMethod(cryptoType);
				int authLen = SRTPUtils.cryptoTypeToAuthLen(cryptoType);

				//System.out.println("cryptoType: "+cryptoType);
				//System.out.println("keyBytes: "+BufferUtils.encodeHexString(keyBytes));
				//System.out.println("saltBytes: "+BufferUtils.encodeHexString(saltBytes));
				//System.out.println("encMethod: "+encMethod);
				//System.out.println("authMethod: "+authMethod);
				//System.out.println("authLen: "+authLen);

				SRTPKeyContext srtpKeyContext = new SRTPKeyContext(encMethod, authMethod, authLen);
				SRTPMasterKey srtpMasterKey = new SRTPMasterKey(keyBytes, saltBytes);

				srtpKeyContext.setMKILen(mkiLen);
				srtpKeyContext.putMasterKey(mki, srtpMasterKey);
				srtpKeyContext.setKeyDerivationRate(keyDerivationRate);

				getLogger().warn("ModuleSRTPPlaybackTest.onRTPSessionCreate: Set encryption info ["+rtpTrack.getTrackId()+"]: keyBytes:"+BufferUtils.encodeHexString(keyBytes)+" saltBytes:"+BufferUtils.encodeHexString(saltBytes));

				rtpTrack.setSRTPKeyContextOut(srtpKeyContext);
				break;
			}
		}
	}

	public void onRTPSessionCreate(RTPSession rtpSession)
	{
		getLogger().info("ModuleSRTPPlaybackTest.onRTPSessionCreate");

		rtpSession.setEncryptionProvider(encryptionProvider);

	}
}
In this case the crypto information will be presented in the RTSP SDP exchange or SDP file data. The ffplay open source tool can be used to test playback.
Originally Published: For Wowza Streaming Engine 4.3.0 on 10-06-2015.
 

If you're having problems or want to discuss this article, post in our forum.