Using Sample AES Encryption for HLS with Unified Origin

This tutorial explains how to configure Unified Origin to encrypt its HLS output with Sample AES encryption. It also demonstrates how you can test the output to check whether you have configured Origin correctly (i.e., whether its HLS output is encrypted and can be played back succesfully given the right environment).

All encryption for HTTP video streaming is AES 128 encryption, which is a symmetric key algorithm. This means that the same key is used to encrypt and decrypt the content. This Content Encryption Key (CEK) consists of 128 random bits (hence 'AES 128').

Note that Sample AES encryption as configured in this tutorial does not equal DRM. Sample AES encryption for HLS output is used for Apple's FairPlay DRM, but that is not what this tutorial is about. It is about using Sample AES encryption only. This means that Origin will encrypt its HLS output accordingly, and add the necessary signaling to the Master Playlist and Media Playlists that it will generate for its HLS output. This signaling includes the URL that the client will need to make a request to in order to get the CEK (so that it can decrypt the content).

Before you start

Before starting please make sure that:

  • Unified Origin is properly installed, which includes 'mp4split' (see: How to Install)

  • You have downloaded the Tears of Steel test content (see: Verify Your Setup)


All of the commands in this tutorial can be run from your user's home directory, but some of them might require you to use sudo, depending on the exact rights of your user and the configuration of your system.

Setting up your test environment

To set up your test environment make sure that Apache is running and that you have stored the tears-of-steel directory with the test content in the DocumentRoot of the Apache virtual host that you configured for Origin. This tutorial presumes that this DocumentRoot is located in the /var/www/ directory (i.e., the test content will be located in /var/www/tears-of-steel).

The options you will need to use

Sample AES encryption for HLS not only uses a CEK, but also uses a Key Initialization Vector (KIV). This KIV makes the encryption more secure by preventing repetitive patterns. Sample AES encryption for HLS does not use a key to the identify the content that is encrypted (often called a 'KID').

When configuring Origin to encrypt its HLS output with Sample AES you must specify a CEK, but you don't have to specify a KIV. If you do not specify a KIV, Origin will generate it automtically.

To specify the CEK, you use the --hls.key option. It takes a combination of a KID and CEK as its arguments (both hex encoded and seperated by a colon). As we do not want to specify a KID in this particular case, we leave that part of the argument for this option empty, like so: --hls.key=:${CEK}.

To specify the KIV, you use the --hls.key_iv option. This simply takes the hex encoded KIV as its arugment, like so: --hls.key_iv=${KIV}.

Two additional options are required to enable Sample AES encryption for Origin's HLS output:

  • --hls.playout=sample_aes to actually specify that Sample AES encryption should be used (as opposed to the older, regular AES 128 encryption)

  • --hls.license_server_url to specify the URL that the client will need to make a request to in order to get the CEK (so that it can decrypt the content)

Create your own keys (CEK and KIV)

If you do not have a specific CEK and KIV that you want to use for the purpose of this tutorial, you can you can use 'openssl' to generate the necessary 'random' 128 bit strings.

The below command will generate a 128 bit (i.e., 16 byte) key in binary format and write it to a file called content.key. Later on in this tutorial, we'll put this file alongside our test content on our server so that it can serve as the endpoint that a client can make requests to to fetch key it needs for decryption.


openssl rand 16 > content.key

We now have our CEK stored in binary format (which is the format that the client needs), but on the command-line we'll need to specify it in hex. To convert it the key stored in the file to hex format, we'll use 'hexdump' and store the result in a variable called CEK:


CEK=$(cat content.key | hexdump -e '16/1 "%02x"')

For our KIV, we'll use the same process except we won't use a file as the intermediary format, because we don't need it:


KIV=$(openssl rand 16 | hexdump -e '16/1 "%02x"')

Move binary format CEK file alongside test content

To make a Sample AES workflow work, the client needs to be able to request the key from a URL that is specified in the (Master and) Media Playlists. This file must contain the CEK in binary format, like we have generated earlier.

We'll now move the file to directory in our DocumentRoot where our test content is stored:


sudo mv content.key /var/www/tears-of-steel

Now that we moved content_encrypt.key alongside the test content, it is accessible from the outside and addressable through a URL. Specify the domain name through which your Origin server can be accessed as origin_url like below and we can store the URL to our CEK in the content_key_url variable:


All preperations have been done now. The last step is to configure the actual stream by creating a server manifest.

Create server manifest to configure your stream

We'll configure this stream with audio in two bit rates, and video in four. We'll also use all of the options mentioned above to enable Sample AES encryption for our HLS output:

  • --hls.key=:${CEK} to specify our CEK

  • --hls.key_iv=${KIV} to specify our KIV

  • --hls.license_server_url=${content_key_url} to specify endpoint for client to fetch CEK from

  • --hls.playout=sample_aes to enable Sample AES encryption for our HLS output

In addition, we'll use the two more general options to further configure our HLS output:

  • --hls.client_manifest_version=4 to make sure our HLS output supports basic features like multiple audio tracks

  • --hls.minimum_fragment_length=4 to explicitly define the length of our HLS segments, instead of relying on the default (the choice is '4' here, because the Tears of Steel test content is encoded with a GOP length of 4 seconds)

This gives us the following command-line to create our server maniefst tos-sample-aes.ism:


mp4split -o tos-sample-aes.ism \
  --hls.key=:${CEK} \
  --hls.key_iv=${KIV} \
  --hls.license_server_url=${content_key_url} \
  --hls.playout=sample_aes \
  --hls.client_manifest_version=4 \
  --hls.minimum_fragment_length=4 \
  /var/www/tears-of-steel/tears-of-steel-aac-64k.mp4 \
  /var/www/tears-of-steel/tears-of-steel-aac-128k.mp4 \
  /var/www/tears-of-steel/tears-of-steel-avc1-400k.mp4 \
  /var/www/tears-of-steel/tears-of-steel-avc1-750k.mp4 \
  /var/www/tears-of-steel/tears-of-steel-avc1-1000k.mp4 \

The last step is to move the server manifest alongside the test content:


sudo mv tos-sample-aes.ism /var/www/tears-of-steel

Now you have completed the setup of your stream with Sample AES encrypted HLS output. Let's test it.

Test your stream

To test whether you have configured everything correctly, you can do two things:

  • Request the Master Playlist to see whether it contains the expected configuration

  • Try playout using Apple's native media player in Safari, or using hls.js

To request the Master Playlist:

curl -v ${origin_url}/tos-sample-aes.ism/.m3u8

The result of which should look, at the top, something like the partially presented Master Playlist below, which is taken from our Sample AES demo setup. Note the line that starts with '#EXT-X-SESSION-KEY', where 'METHOD' specifies 'SAMPLE-AES' and 'URI' points to the URL where the client can fetch the CEK:

## Created with Unified Streaming Platform (version=1.10.20-20861)

# AUDIO groups


If you get the expected response, you should be able to play back your stream as well. Simply visit the URL to the Master Playlist in Safari and it should start automatically.

If it doesn't, one simple thing to check is whether you can make a successful request to the URL that points to the CEK, as signaled in your Master Playlist.

Also, to compare it with another Sample AES encrypted HLS stream generated by Origin, you can always use the one from our demo setup:

curl -v

Finally, you can always contact us if you have any questions: