Article: How to secure Apple HTTP Live Streaming (AES-128 - external method)

Thanks for the update, Abed.

Richard

Do you have SSL configured?

It might help you to add the Access-Control-Allow-Origin http header by adding this to the Application.xml /HTTPStreamer Properties container:

<Property>
	<Name>cupertinoUserHTTPHeaders</Name>
	<Value>Access-Control-Allow-Origin: *</Value>
</Property>

Richard

This is a duplicate, Sanjeev

Indika,

You can also look at this discussion I started here: https://www.wowza.com/forums/showthread.php?10236-iPhone-authentication-for-vod-stream&highlight=

It discusses a way to secure streams down without generating a key for each one. Start on page 3.

Jake

Hi,

I wonder what parameters should be passed to genkey if I want to have AES encryption for smil that contains several live streams:

http://[wowza-address]:1935/hls/smil:multistream.smil/playlist.m3u8
genkey iphone multistream.smil [key-url] ??

or do I have to create separate key for each stream?

Best!

@mcaron, did you find how to proceed ?

It has to be done for each stream in the smil. You don’t do it for the smil itself, which is just a text file the playback client uses to know what streams are available.

Richard

Ok, so i need to create a key for each video ?

Not the possibility to have 1 key for all videos for the same application ?

Hello,

I followed this example: iPhone/iPad iOS - (AES-128-external-method) and it worked great for the VOD application, but I’m having trouble getting it to work for a liverepeater-edge application

Application.xml - configuration

<Root>
	<Application>
		<!-- Uncomment to set application level timeout values
		<ApplicationTimeout>60000</ApplicationTimeout>
		<PingTimeout>12000</PingTimeout>
		<ValidationFrequency>8000</ValidationFrequency>
		<MaximumPendingWriteBytes>0</MaximumPendingWriteBytes>
		<MaximumSetBufferTime>60000</MaximumSetBufferTime>
		<MaximumStorageDirDepth>25</MaximumStorageDirDepth>
		-->
		<Connections>
			<AutoAccept>true</AutoAccept>
			<AllowDomains></AllowDomains>
		</Connections>
		<!--
			StorageDir path variables
			
			${com.wowza.wms.AppHome} - Application home directory
			${com.wowza.wms.ConfigHome} - Configuration home directory
			${com.wowza.wms.context.VHost} - Virtual host name
			${com.wowza.wms.context.VHostConfigHome} - Virtual host config directory
			${com.wowza.wms.context.Application} - Application name
			${com.wowza.wms.context.ApplicationInstance} - Application instance name
			
		-->
		<Streams>
			<StreamType>liverepeater-edge</StreamType>
			<StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir>
			<KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys/${com.wowza.wms.context.Application}/${com.wowza.wms.context.ApplicationInstance}</KeyDir>
			<!-- LiveStreamPacketizers (separate with commas): cupertinostreamingpacketizer, smoothstreamingpacketizer, cupertinostreamingrepeater, smoothstreamingrepeater -->
			<LiveStreamPacketizers>cupertinostreamingrepeater</LiveStreamPacketizers>
			<!-- Properties defined here will override any properties defined in conf/Streams.xml for any streams types loaded by this application -->
			<Properties>
			</Properties>
		</Streams>
		<!-- HTTPStreamers (separate with commas): cupertinostreaming, smoothstreaming -->
		<HTTPStreamers>cupertinostreaming</HTTPStreamers>
		<SharedObjects>
			<StorageDir></StorageDir>
		</SharedObjects>
		<Client>
			<IdleFrequency>-1</IdleFrequency>
			<Access>
				<StreamReadAccess>*</StreamReadAccess>
				<StreamWriteAccess>*</StreamWriteAccess>
				<StreamAudioSampleAccess></StreamAudioSampleAccess>
				<StreamVideoSampleAccess></StreamVideoSampleAccess>
				<SharedObjectReadAccess>*</SharedObjectReadAccess>
				<SharedObjectWriteAccess>*</SharedObjectWriteAccess>
			</Access>
		</Client>
		<RTP>
			<!-- RTP/Authentication/[type]Methods defined in Authentication.xml. Default setup includes; none, basic, digest -->
			<Authentication>
				<PublishMethod>none</PublishMethod>
				<PlayMethod>digest</PlayMethod>
			</Authentication>
			<!-- RTP/AVSyncMethod. Valid values are: senderreport, systemclock, rtptimecode -->
			<AVSyncMethod>senderreport</AVSyncMethod>
			<MaxRTCPWaitTime>12000</MaxRTCPWaitTime>
			<IdleFrequency>75</IdleFrequency>
			<RTSPSessionTimeout>90000</RTSPSessionTimeout>
			<RTSPMaximumPendingWriteBytes>0</RTSPMaximumPendingWriteBytes>
			<RTSPBindIpAddress>[edge-address]</RTSPBindIpAddress>
			<RTSPConnectionIpAddress>[edge-address]</RTSPConnectionIpAddress>
			<RTSPOriginIpAddress>[edge-address]</RTSPOriginIpAddress>
			<IncomingDatagramPortRanges>*</IncomingDatagramPortRanges>
			<!-- Properties defined here will override any properties defined in conf/RTP.xml for any depacketizers loaded by this application -->
			<Properties>
			</Properties>
		</RTP>
		<MediaCaster>
			<!-- Properties defined here will override any properties defined in conf/MediaCasters.xml for any MediaCasters loaded by this applications -->
			<Properties>
			</Properties>
		</MediaCaster>
		<MediaReader>
			<!-- Properties defined here will override any properties defined in conf/MediaReaders.xml for any MediaReaders loaded by this applications -->
			<Properties>
			</Properties>
		</MediaReader>
		<MediaWriter>
			<!-- Properties defined here will override any properties defined in conf/MediaWriter.xml for any MediaWriter loaded by this applications -->
			<Properties>
			</Properties>
		</MediaWriter>
		<LiveStreamPacketizer>
			<!-- Properties defined here will override any properties defined in conf/LiveStreamPacketizers.xml for any LiveStreamPacketizers loaded by this applications -->
			<Properties>
				<Property>
					<Name>forceH264BaselineProfile</Name>
					<Value>true</Value>
					<Type>Boolean</Type>
				</Property>
			</Properties>
		</LiveStreamPacketizer>
		<HTTPStreamer>
			<!-- Properties defined here will override any properties defined in conf/HTTPStreamers.xml for any HTTPStreamer loaded by this applications -->
			<Properties>
			</Properties>
		</HTTPStreamer>
		<Repeater>
			<OriginURL>rtmp://[origin-server-address]/[application-name]</OriginURL>
			<QueryString><![CDATA[]]></QueryString>
		</Repeater>
		<Modules>
			<Module>
				<Name>base</Name>
				<Description>Base</Description>
				<Class>com.wowza.wms.module.ModuleCore</Class>
			</Module>
			<Module>
				<Name>properties</Name>
				<Description>Properties</Description>
				<Class>com.wowza.wms.module.ModuleProperties</Class>
			</Module>
			<Module>
				<Name>logging</Name>
				<Description>Client Logging</Description>
				<Class>com.wowza.wms.module.ModuleClientLogging</Class>
			</Module>
			<Module>
				<Name>flvplayback</Name>
				<Description>FLVPlayback</Description>
				<Class>com.wowza.wms.module.ModuleFLVPlayback</Class>
			</Module>
		</Modules>
		<!-- Properties defined here will be added to the IApplication.getProperties() and IApplicationInstance.getProperties() collections -->
		<Properties>
		</Properties>
	</Application>
</Root>

the stream works using http://[repeater-address]:1935/[application-name]/[application-instance-name]/[stream-name]/playlist.m3u8

I have the key named [stream-name].key in the /keys/[application-name]/[application-instance-name]/ directory and the url to the [stream-name].php which supplies the key is active and working (just like it worked for the VOD app), my problems is that the stream is not encrypted and will play with a valid or invalid key in the [stream-name].php file.

One thing i noticed was that if I change the stream (there are multiple streams running on the origin on multiple application-instances) Wowza creates the key/[application-name]/[application-instance-name]/ directory looking for they key.

Is this possible or must I update the Origin Application.xml conf file to match?

Hello Richard,

I tried what you suggested and still no success, the stream still works regardless of keys.

I even fooled around with the [stream-name].stream link and removed some parts of the Application.xml file like:

		<Repeater>
			<OriginURL></OriginURL> <!-- rtmp://[origin-server-address]/[application-name] used to be here -->
			<QueryString><![CDATA[]]></QueryString>
		</Repeater>

just to be sure Wowza used the [steam-name].stream file and it does, but still no encryption…

for the VOD example Wowza displays the following in the log:

#EXTM3U
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-KEY:METHOD=AES-128, URI="http://[web-server-address]/[supply-key].php?wowzasessionid=[id]"
#EXTINF:11

For the LIVE example all i get is:

#EXTM3U
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:6239
#EXTINF:2

Hi all,

I am trying to encrypt a transcoded (MPEG4 -> H.264) live stream for iPad, with no success though. What should be the filename for the key file?

Currently I use keys/enc.stream.key. However, the content link is: http://wowzaIP:1935/crypt/ngrp:enc.stream_mobile/playlist.m3u8

The content is not encrypted. The VOD case, without transcoding works fine.

Thanks in advance!

You have to encrypt each item in the ngrp group, but not the ngrp group itself. Test each one individually.

Thanks, but I didn’t get it, sorry.

Currently I can find this in access logs:

2012-01-10      13:29:41        CET     comment server  INFO    200     -       LiveStreamPacketizerCupertino.init[crypt/_definst_/enc.stream]: Encrypt Cupertino stream: key: *A1D2

In the ngrp groups I have this:

Groups:

enc.stream_mobile[remove stream group]

160p

enc.stream_all[remove stream group]

160p

What are the items of the group and how to encrypt them?

How should be named the file with encryption key?

ok, it works now, with disabled relative addressing and key filename: enc.stream_160p.key

thanks a lot.

I’m trying to set up a Cupertino VOD file for simple secure streaming to a iPad application in Phonegap 1.2.0.

My local ip is 10.120.1.157 so I’ll use that for my example. I’ve encrypted the file sampleblocked.mp4 using

./genkey.sh ipad sampleblocked.mp4 http://10.120.1.157:1935

Returning:

cupertinostreaming-aes128-key: F96B05094642E835D09AF434CFD55DE1

cupertinostreaming-aes128-url: http://10.120.1.157:1935/video.php

I’ve moved the resulting key file sampleblocked.mp4.key into the [wowzaroot]/keys directory.

Where I’m confused is what I should use to call the encrypted VOD file so it will play.

If I use:


the iPad app appropriately returns “The operation could not be completed”

But I don’t understand what code should be used to get this file to play.

I assumed it might be:

http://10.120.1.157:1935/video.php?keyinfo=F96B05094642E835D09AF434CFD55DE1

but that doesn’t work. :confused:

Thanks for any pointers and best regards–

Dennis

Haveyou been able to solve this? please can you post the solution how to call the video from wowza with key send step by step.

It still needs to be documented. I don’t have a time frame for this. Check this group of articles:

Wowza Streaming Engine DRM

It will show up there when it is published.

Richard

I understand you may not yet have a time frame for when documentation for key rotation will go up. Just posting to let you know there’s at least one more party interested in this.

Will keep checking that group of articles over time.

Thanks.

Is there a way to remove wowzasessionid=xxxxxxx parameter in the playlist generated by wowza for the key url. For example if we would like to use a local file as a key like this:

#EXT-X-KEY:METHOD=AES-128,URI=“file://data/misc/safeview/36.key?wowzasessionid=24173829”,KEYFORMATVERSIONS=“1”

It will not work if it has the session id since it will be looking for the file 36.key?wowzasessionid=24173829 instead of 36.key

What means would the external script have to know if Wowza is in an approved or pirated session?

Wowza calls the external script when the HLS session is started. If it does not respond with the key the session will not work.

Richard

Hello Rchard-san,

This is Iwata.

I am afraid Iam not good at English.

I have same problem too.

now status is the following.

(1) WMS3.0 + Transcoder (in One server)

=> external encrypt on live stream is OK.

safari on iOS was normal requested to CGI URL in key file.

CGI is set on WMS3.0+Transcoder.

(2) WMS3.0 + Transcoder (origin) → WMS3.5(edge)

=> external encrypt is NG.

this pattern,

safari on iOS was not requested to CGI URL in key file.

CGI is set on WMS3.5(edge).

but, I was look the following log in wowzamediaserver_access.log.


INFO server comment - LiveStreamPacketizerCupertino.init[liveedge/definst/recsmart.stream_240p_test]:

Encrypt Cupertino stream: key: *F367 url: http://[WMS3.5(edge)IPaddress]/cgi-bin/recsmartcheck_240p_test.cgi


Moreover, about (2) , we were set the vod and key files to the server.

but it was successfull.

Please help me solving about (2) problem.

configration of (2)"WMS3.5(edge) is the following.

[installdir]/conf/liveedge/Application.xml

liverepeater-edge

${com.wowza.wms.context.VHostConfigHome}/content

${com.wowza.wms.context.VHostConfigHome}/keys

cupertinostreamingrepeater,smoothstreamingrepeater,sanjosestreamingrepeater

cupertinostreaming,smoothstreaming,sanjosestreaming

wowz://[(1)WMS3.0+Tanscoder IPAddress]:1935/live

[installdir]/keys/recsmart.stream_240p_test.key

cupertinostreaming-aes128-key: F88BB4132F4A864FE9D4EC2918BEF367

cupertinostreaming-aes128-url: http://[(2)WMS3.5(edge)IPAddress]/cgi-bin/recsmartcheck_240p_test.cgi

Best regards,

Iwata

What is [stream-name] ? Is it a simple name like “myStream”, and you have the rtmp address of the origin in /originURL?

If so, try using a .stream file instead. Create a text file named origin.stream in the content folder:

/content/origin.stream, with contents:

rtmp://[wowza-address]:1935/liveorigin/definst/myStream

Now use stream name “origin.stream”

Richard

Hi Richard,

Thank you very much for reply.

.cgi script is reachable.

I was searched on access.log of web server, but I not found for .cgi access log.

but I was access successfull to this cgi via Web browser.

Moreover, I tried same method to vod contents, but it is successfull.

Is this external encrypt method not support to liveedge?:confused:

Best regards,

Iwata

Hi Iwata,

I’m not sure what the problem is. Is the .cgi script reachable?

Does streaming work? I assume that AES encryption is not working…?

Richard

Hi Richard,

Does streaming work? I assume that AES encryption is not working…?

streaminig is working.

and it is successfull by the following flow.

WMS3.0+TranscoderAddon(live) → WMS3.5(liveedge)–>(HLS without external AES Encrypt)–> iOS6.X

Best regards,

Iwata

Hi Iwata,

I’m not sure what the problem is. Is the .cgi script reachable?

Does streaming work? I assume that AES encryption is not working…?

Richard

Alright, I set up the external method, however I am running into an issue with ios devices. It throws an invalid security certificate error could this have to do with the key or the authentication php form? I am bit confused Would like a bit of clarification if possible

Hi Richard,

I am new to wowza, trying to achieve AES encryption with the external method, I have read through this entire post and all the comments, I am listing down steps which I am using to proceed with encryption and also queries, please let me know for those.

  1. Generate a key that is used to encrypt each of the media chunks.
  • key name is streamname.key

  • created using

cd C:\Program Files (x86)\Wowza Media Systems\Wowza Streaming Engine 4.0.3\bin>

command> genkey.bat {playerOS}iphone {streamname}sample.mp4 {how will the player read the key}http://*host/Test/mf-key.php

  1. The key file include a URL for the player to retrieve the key.

  2. Put the key in the keys folder on the server and it’s name matches the name of the media file.

  3. Wowza will use the key to encrypt each of the chunks before delivery and will put the key URL in the playlist file so the player can

retrieve the key to decrypt the chunks.

  1. You provide a PHP script in your web server that distrubutes the key. You need to be sure you secure the key so only who you want to view the stream can get the key.

  2. This applies to both live and video on demand streams.

  3. Test it as follows.

  • For IOS Include the path in

  • To test using desktop versions use jwplayer enterprise edition

jwplayer(‘player’).setup({

wmode: “transparent”,

height: “360”,

autostart: ‘false’,

//skin: ‘bekle’,

playlist: [{

sources: [{

file: “http://[wowza-ip]:1935/vod/mp4:sample.mp4/playlist.m3u8”

}]

}],

});

Queries

  • Do we have to generate a .key file per stream ? If so can you help understanding how can it be achieved using php on uploading of each vod content.?

  • Does the .key file necessary be in wowza/keys folder or cant it be mounted to a NFS ? as in my case the transcoding is being done and all streams are accessible via nfs mounted between wowza,applciation and a cdn

  • Can a key file generated for iphone be used for ipad and itouch or a separate key needs to be generated for each of this ?

  • Will a DRM addon be recommended for encrypting streams on the fly or AES is a better approach. Please advice.

Many Thanks

Sanjeev