Wowza Community

Secure streaming to the iPhone and iPod Touch (AES-128 - external method)

https://www.wowza.com/docs/how-to-secure-apple-http-live-streaming-aes-128-external-method

Both methods (internal and external) should still work on all iOS versions greater or equal to 3.0.

Charlie

Charlie,

The links to:

Streaming to the iPhone and iPod Touch

SHOUTcast, RTSP/RTP, native RTP or MPEG-TS streaming to iPhone and iPod Touch

Seems to be broken / dead. Can you please check it out? I need to reconfigure live iphone streaming to a new server.

Thanks!

-fred

You mentioned that iPhone/iPod touch OS Version 3.0 is required for the external method. I wasn’t sure if that limitation was written before OS Version 4 was released, so I am wondering if you know whether the external method continues to work on iPhones with OS 4?

If not, any suggested workarounds would be appreciated.

Thanks!

Let me see if this helps. The basic idea is:

  • Generate a key that is used to encrypt each of the media chunks. The key file includs a URL for the player to retrieve the key.

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

  • 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.

  • 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.

    This applies to both live and video on demand streams.

    Charlie

For video on demand if the keys are setup properly you should see the same type of message saying the stream is protected. If you don’t see the message then it is not setup properly.

Take a look at this post for a way to have the key generated dynamically:

http://www.wowza.com/community/t/-/67

Charlie

Basically the key is the key. You have to figure out how to protect the key. With the chunks of media encrypted now the valuable asset is the key. So you need to invent a scheme for protecting the key. For VOD with the internal method it is possible to generate a different key for each session. So that is even more secure.

Charlie

Use these instead:

vod streaming

http://www.wowza.com/community/t/-/64

live streaming

https://www.wowza.com/docs/how-to-set-up-live-streaming-using-an-rtmp-based-encoder

mgpeg-ts

https://www.wowza.com/docs/how-to-publish-and-play-a-live-stream-mpeg-ts-based-encoder

rtsp

https://www.wowza.com/docs/how-to-set-up-live-streaming-using-an-rtmp-based-encoder

others among these:

http://www.wowza.com/community/c/-/8

Richard

A solution to “link sharing”, if I understand what you mean, could be expiring keys. You would have to develop something involving a database and timestamps, probably.

Richard

In looking at the external method it looks like the main item is making sure you configure your key-url properly with ASP.NET, JSP or PHP. Correct?

With the internal method it appears to be a little more work since you have to compile your module in the Wowza IDE. Right?

I just want to make sure I understand both processes correctly.

Thanks,

Derrick

I am having some issues understand exactly how this works. It would seem the example is primarily created for securing live streams, however I am still new to Wowza so I could be wrong. I have a lot of questions but I guess I will start with the first question because hopefully by answering that I will have a better idea on how to proceed.

A quick bit about my current setup… I warn you it is very simple…

I have a php file called mediaplayer.php and all it does is simply link directly to the stream… so for instance when the user selects the media file they wish to stream a link is basically generated using the exact example given in the tutorials…

Launch Video

$media is being passed through the URL, so the URL would look like

http://192.168.1.101/iphone/mediaplayer.php?media=testvideo1

I could get rid of the a href link all together and simply forward the user there like so…

<?php ob_start(); header("Location: http://[wowza-address]:1935/vod/mp4:".$media.".mp4/playlist.m3u8"); ?>

So first off, this is the example given in this post to generate a key for a given stream is…

genkey.bat iphone myStream.sdp https://mycompany.com/myStream.php

From what I have read sdp seems to be for live streams. How would I generate a key for a VOD file? Would I have to generate a key for each video file that I am streaming to secure it?

I have generated a few keys for some of the media files but I can still access them by browsing directly to them in my iphone…

(http://[wowza-address]:1935/vod/mp4:Extremists.m4v/playlist.m3u8)

Unlike the live streams, I don’t see a message from Wowza saying the stream is encrypted.

Also, this raises another concern. All of the keys seem to be hardcoded into the PHP file. What if I have 200 media files I want to share? Would I need to manually create 200 key files, then hardcode those 200 keys into the php file?

I actually have over 25,000 media files that are compatible with the iPhone. Currently I use FMS 3.5 to stream the files using flash through the browser. Imagine my surprise when I found out that Wowza could stream the entire archive to the IPhone because the encodes are compatible. I am trying to make the switch from FMS 3.5 to stream to both PC users and the iPhone, but it would seem that this method is cumbersome at best when dealing with large numbers of media files that are accessed on demand. Obviously I can secure the streams the same was I do im FMS, utilizing tokens and such, but the iPhone doesn’t work that way.

What method would you suggest to be the most effective for securing videos on demand streamed to the iphone when working with massive amounts of content that is changing regularly? I would love to be able to secure the videos because I could instantly switch over to Wowza. However, without being able to secure the streams in a method that is not only effective but somewhat manageable I won’t be able to. Any advice whatsoever would be GREATLY appreciated.

I am still failing to see how either method would prevent link sharing for instance. If one user knows the path to generate the playlist file it will encrypt the stream but it won’t keep unwanted users from gaining access would it? If they know the url to generate the playlist, it would encrypt the stream but the link to open the stream would have to include the key to decrypt the stream.

Maybe I am way off, if so please let me know… but what would keep unwanted users from viewing the stream if key was located in the playlist file?

This question is for Charlie. First, I understand that the examples provided in this tutorial are “provided as is with no expressed warranty”. Now, I have set up secure streaming for iphone with the external php to distribute the key. The setup works with the provided php example, it plays when set to true and rejects when set to false. The problem I am having is that when I replace the if conditional statement in the example with my own if statement (statement has been tested and confirmed working on its own) the stream will reject correctly when user not logged in but when user is logged in the player attempts to play the video and seems to crash. The reason I believe it is crashing is because it will show the stream starting to play and sound even tries to play. I have been working on this for hours and hours, I have taken it apart and put it back together several times in several different ways with different statements that have been tested independently and I always get the same error. This error is different than when the key does not reach the browser or when the statement is null because these errors will actually bring up a prompt from the player that says “The stream cannot be player” or “You are not authorized to view this stream”. I have spent countless hours reviewing the posts on this forum and any other information I could find online to no avail. I am reaching out to the experts and the community for any help as I am desperate.

Here is my php code for the key distribution:

[PHP]<?php

define( ‘_JEXEC’, 1 );

define(‘JPATH_BASE’, dirname(FILE) );

define( ‘DS’, DIRECTORY_SEPARATOR );

require_once JPATH_BASE.DS.‘includes’.DS.‘defines.php’;

require_once JPATH_BASE.DS.‘includes’.DS.‘framework.php’;

jimport( ‘joomla.application.application’ );

require_once ( JPATH_BASE .DS.‘includes’.DS.‘application.php’ );

$mainframe =& JFactory::getApplication(‘site’);

$mainframe->initialise();

$jUser = &JFactory::getUser();

function hex2bin($h)

{

if (!is_string($h))

return null;

$r = ‘’;

for ($a=0;$a<strlen($h);$a+=2)

{

$r .= chr(hexdec($h{$a}.$h{($a+1)}));

}

return $r;

}

if ($jUser->get(‘gid’) < 1 )

{

header(‘HTTP/1.0 403 Forbidden’);

}

else

{

header(‘Content-Type: binary/octet-stream’);

header(‘Pragma: no-cache’);

echo hex2bin(‘865D26D502D3E31C67EABEDE6730A53D’);

exit(); // this is needed to ensure cr/lf is not added to output

}

?>[/PHP]

All of the code above the function hex2bin is to load the infrastructure necessary to authenticate users, I have independently tested it and it does not appear to be interfering with the key process. It is only when I change the $isValid bool to my own conditional statement that the problem appears. If there is an option to receive specialized support from wowza media systems let me know what I need to do opt in on that, as it is very important that I resolve this issue as soon as possible.

Went at the problem again today and was able to resolve it. It appears that when I would change the original bool in the php example it would affect the output of the key in some way that I was never able to identify. So I left the original bool intact and added my if statement outside of the original script and that solved the issue. Here is my final code just in case it helps anybody with a similar problem.

[PHP]<?php

define( ‘_JEXEC’, 1 );

define(‘JPATH_BASE’, dirname(FILE) );

define( ‘DS’, DIRECTORY_SEPARATOR );

require_once JPATH_BASE.DS.‘includes’.DS.‘defines.php’;

require_once JPATH_BASE.DS.‘includes’.DS.‘framework.php’;

jimport( ‘joomla.application.application’ );

require_once ( JPATH_BASE .DS.‘includes’.DS.‘application.php’ );

$mainframe =& JFactory::getApplication(‘site’);

$mainframe->initialise();

$jUser = &JFactory::getUser();

if ($jUser->get(‘gid’) < 1)

{

header(‘HTTP/1.0 403 Forbidden’);

}

function hex2bin($h)

{

if (!is_string($h))

return null;

$r = ‘’;

for ($a=0;$a<strlen($h);$a+=2)

{

$r .= chr(hexdec($h{$a}.$h{($a+1)}));

}

return $r;

}

$isValid = true;

if (! $isValid)

{

header(‘HTTP/1.0 403 Forbidden’);

}

else

{

header(‘Content-Type: binary/octet-stream’);

header(‘Pragma: no-cache’);

echo hex2bin(‘865D26D502D3E31C67EABEDE6730A53D’);

exit(); // this is needed to ensure cr/lf is not added to output

}

?>[/PHP]