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

    This article provides step-by-step instructions for using the external method in Wowza Streaming Engine™ software to configure secure streaming of a live or video on demand (VOD) stream to Apple iOS devices.

    Notes:


    When you use the external method of AES-128 encryption, encryption keys are delivered by using an external URL. There is also an internal method that uses Wowza Streaming Engine to deliver all media chunks and encryption keys. For more information about how to use the internal method, see How to use the internal method of AES-128 encryption to secure a live or VOD stream to sent to Apple iOS devices (ModuleEncryptionHandlerCupertinoStreaming).

    Configuration

    1. Start by configuring a Wowza Streaming Engine application for streaming by following one of our video on demand or live streaming tutorials. You will also need access to a web server.

    2. Create a key file in the [install-dir]/keys folder for each stream you want to encrypt. The key file is a text file with the name of the stream you want to protect and a .key extension. For example, to encrypt a live stream named myStream, create a key file in the [install-dir]/keys folder named myStream.key with content similar to the following:
      cupertinostreaming-aes128-key: DE51A7254739C0EDF1DCE13BBB308FF0
      cupertinostreaming-aes128-url: http:/mycompany.com/security.aspx
      • cupertinostreaming-aes128-key is a 32-byte key that will match the key used to decrypt the stream. You will want to replace this key with one of your own.
      • cupertinostreaming-aes128-url is the URL that devices will use to fetch the key to decrypt the stream, as shown in the examples below. You can control who can view your stream by managing access to this URL.

      You must have a .key file for each stream that you want to protect. Each of these files may use the same 32-byte key and the same URL to return that key to devices, or you might have a different key and different URL for each stream.

      Note: You can also use the genkey utility to generate key files. A key file with a different key is generated each time you run this utility. You can integrate this utility into an automated workflow to create many .key files for a video library.


    The key must be returned to a device as a packed array of 16 octets in binary format with the following header information:
    Content-Type: binary/octet-stream
    Pragma: no-cache

    Examples

    The following examples show how to use popular web application technologies such as ASP.NET, JSP, and PHP to send the key data. Each of these examples includes a Boolean isValid value that defaults to true. You can modify these examples to provide your own security tests to validate that the user can access the content. If the user should not be allowed to access the content, you can block them from receiving the decryption key by setting the isValid value to false.

    If the request for this key returns a status of 403, then the device cannot decrypt and play the stream. If the key is returned, then the stream will be decrypted and played. Require HTTPS access to this key so that it is not sent over an unsecured connection on the Internet.

    The key being sent in these examples is DE51A7254739C0EDF1DCE13BBB308FF0. Substitute this value with the 32-byte key set in the .key file in the Configuration section.

    Note: These examples are provided as-is with no expressed warranty. You can modify or distribute them without restriction.

    ASP.NET example

    <%@ Page Language="C#" %>
    <%
    
    	Boolean isValid = true;
    	if (!isValid)
    	{
    		Response.Status = "403 Forbidden";    
    	}
    	else
    	{
    		Response.AddHeader("Content-Type", "binary/octet-stream");
    		Response.AddHeader("Pragma", "nocache");
    
    		String keyStr = "DE51A7254739C0EDF1DCE13BBB308FF0";
    
    		int len = keyStr.Length/2;  
    		byte[] keyBuffer = new byte[len];  
    
    		for (int i=0;i<len;i++)
    			keyBuffer[i] = Convert.ToByte(keyStr.Substring(i*2, 2), 16);
    
    		Response.BinaryWrite(keyBuffer);
    		Response.Flush();
    		Response.End();
    	}
    	
    %>

    JSP example

    <%@ page import="java.util.*,java.io.*" %>
    <%
    
    	boolean isValid = true;
    	if (!isValid)
    	{
    		response.setStatus( 403 ); 
    	}
    	else
    	{
    		response.setHeader("Content-Type", "binary/octet-stream");
    		response.setHeader("Pragma", "no-cache");
    
    		String keyStr = "DE51A7254739C0EDF1DCE13BBB308FF0";
    
    		int len = keyStr.length()/2;
    		byte[] keyBuffer = new byte[len];  
    
    		for (int i=0;i<len;i++)
    			keyBuffer[i] = (byte)Integer.parseInt(keyStr.substring(i*2, (i*2)+2), 16);
    
    		OutputStream outs = response.getOutputStream();
    		outs.write(keyBuffer);
    		outs.flush();
    	}
    	
    %>

    PHP example

    <?php
    
    // Check if function exists (php5.4+ includes this method)
    if(!function_exists("hex2bin")){
            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('DE51A7254739C0EDF1DCE13BBB308FF0');
    
    	exit(); // this is needed to ensure cr/lf is not added to output
    }
    
    ?>
    To validate encryption for a live stream, you will see log messages in the Wowza media server access log similar to the following when the stream is published:

    LiveStreamPacketizerCupertino.init[live/_definst_/myStream]: Encrypt Cupertino stream: key: *55BB url: http://192.168.1.120:1935/live/_definst_/myStream/key{sessionid}.m3u8key

    To validate encryption for video on demand streaming, you will see a log message similar to the following example in the Wowza media server access log when an HLS (cupertino) playback session starts:

    HTTPStreamerCupertinoIndexFile.init[vod/_definst_/sample.mp4]: Encrypt Cupertino stream: key: *763a url: http://192.168.1.120:1935/vod/_definst_/mp4:sample.mp4/key{bitrate}{sessionid}.m3u8key

    Using genkey

    Wowza Streaming Engine software includes the genkey utility that you can use to generate key files.

    1. Open a command shell and change directory to [install-dir]/bin.

    2. Enter the following command:

      Windows:
      genkey.bat iphone [stream-name] [key-url]
      Linux:
      ./genkey.sh iphone [stream-name] [key-url]
      Where [stream-name] is the name of the stream that will be encrypted and [key-url] is the URL that an iOS device will use to receive the key data (see specifics about the [key-url] below). This command will generate the file [stream-name].key. An example command line is:
      genkey.bat iphone myStream https://mycompany.com/myStream.php
      The output should look this:
      key: B9A954F22ACD093BDEB80622EC7155BB
      url: https://mycompany.com/myStream.php
      
      Key file generated: myStream.key
      Copy file to: [install-dir]/keys
    3. Copy the file generated in the previous step. You will find this file in the [install-dir]/bin folder. Copy it to the [install-dir]/keys folder. This will protect a stream with that name in any application. See below for details about how to set up an application-specific keys folder.


    keys folder

    By default, all applications are configured to use the same keys folder, which can lead to stream name conflicts. To configure a keys folder on a per-application basis, open [install-dir]/conf/[application]/Application.xml in a text editor and make the Streams/KeyDir property value empty.
    <KeyDir></KeyDir>
    When KeyDir is empty, Wowza Streaming Engine will look in [install-dir]/applications/[application]/keys/[appInstance] for your .key files. You can also use the StorageDir path variables shown in Application.xml to construct other locations.

    Key URL

    Query parameters passed as part of the playlist.m3u8 URL (as well as the wowzasessionid) will be passed to the key URL. For example, if you play a stream using the following URL:

    http://[wowza-ip-address]:1935/live/myStream/playlist.m3u8?userid=12345

    And the key URL is defined as the following URL:

    https://mycompany.com/myStream.php?keyinfo=securekey

    Then the URL sent to myStream.php will include the following query parameters:

    https://mycompany.com/myStream.php?keyinfo=securekey&userid=12345&wowzasessionid=345234

    Note: To test AES encryption, see How to test AES encryption for Apple HLS streams.

    Originally Published: 10-01-2010.
    Updated: For Wowza Streaming Engine on 02-11-2014.

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