How to Encrypt Video for HLS

In this post, we’ll look at what encryption HLS supports and how to encrypt your videos with ffmpeg.

Encryption is the process of encoding information in such a way that only authorised parties can read it. The encryption process requires some kind of secret (key) together with an encryption algorithm.

There are many different types of encryption algorithms but HLS only supports AES-128. The Advanced Encryption Standard (AES) is an example of a block cipher, which encrypts (and decrypts) data in fixed-size blocks. It’s a symmetric key algorithm, which means that the key that is used to encrypt data is also used to decrypt it. AES-128 uses a key length of 128 bits (16 bytes).

HLS uses AES in cipher block chaining (CBC) mode. This means each block is encrypted using the cipher text of the preceding block, but this gives us a problem: how do we encrypt the first block? There is no block before it! To get around this problem we use what is known as an initialisation vector (IV). In this instance, it’s a 16-byte random value that is used to intialize the encryption process. It doesn’t need to be kept secret for the encryption to be secure.

Before we can encrypt our videos, we need an encryption key. I’m going to use OpenSSL to create the key, which we can do like so:

$ openssl rand 16 > enc.key

This instructs OpenSSL to generate a random 16-byte value, which corresponds to the key length (128 bits).

The next step is to generate an IV. This step is optional. (If no value is provided, the segment sequence number will be used instead.)

$ openssl rand -hex 16

Make a note of the output as you’ll need it shortly.

To encrypt the video we need to tell ffmpeg what encryption key to use, the URI of the key, and so on. We do this with -hls_key_info_file option passing it the location of a key info file. The file must be in the following format:

Path to key file
IV (optional)

The first line specifies the URI of the key, which will be written to the playlist. The second line is the path to the file containing the encryption key, and the (optional) third line contains the initialisation vector. Here’s an example (enc.keyinfo):

Now that we have everything we need, run the following command to encrypt the video segments:

ffmpeg -y \
    -i \
    -hls_time 9 \
    -hls_key_info_file enc.keyinfo
    -hls_playlist_type vod \
    -hls_segment_filename "fileSequence%d.ts" \

Take a look at the generated playlist (prog_index.m3u8). It should look something like this:


Note the URI of the encryption key. The player will retrieve the key from this location to decrypt the media segments. To protect the key from eavesdroppers it should be served over HTTPS. You may also want to implement some of authentication mechanism to restrict who has access to the key. If you’re interested, the book goes into some detail about how to achieve this. Click here to buy a copy.

To verify that the segments really are encrypted, try playing them using a media player like QuickTime or VLC. You shouldn’t be able to. Now run the command above without the encryption and then try playing a segment. Notice the difference.

Even though HLS supports encryption, which provides some sort of content protection, it isn’t a full DRM solution. If that kind of thing interests you then you may want to take a look at Apple’s FairPlay Streaming solution.

11 thoughts on “How to Encrypt Video for HLS

  1. Mehmood

    Hi Simon,
    Your post is great. I am new to HLS and your site is really helpful.
    I have a question. How can I use mediafilesegmenter to encrypt every segment of the file with different key ? Apple docs says such thing is supported but I couldn’t find any help regarding it.

    It would be great if you can guide about it, provide command of it.

    1. sbuckle Post author

      Hi Mehmood,

      You can use the -key-rotation-period option of mediafilesegmenter. It takes as an argument a number that specifies how many segments to encrypt before generating a new key. If you want to encrypt every segment with a different key then I guess you will need to set it to 1.

      There’s more information in the Security chapter of the book if you are interested.


  2. Rj

    Hi Simon

    I am new to HLS AES encryption can i get the example of the above procedure in the book meaning a video file taken and encryption explained in step by step fashion including openssl and ffmpeg

    Thanks however for this informative article


  3. Steve

    Hi Simon, I hope this thread is still active. I’m new to ffmpeg and tried the commands you mentioned to encrypt HLS with an openssl key, and it all worked. But one basic question- how do I direct the all the encrypted HLS chunks to a separate folder? In your script they just end up in the folder where I ran the script, so its a little messy. Many thanks

    1. Simon Post author

      Hi Steve,

      You can specify a relative or absolute path to the HLS segments. The following example will output the segments in a directory relative to the location where you run the command:

      ffmpeg -y \
          -i \
          -hls_time 9 \
          -hls_key_info_file enc.keyinfo \
          -hls_playlist_type vod \
          -hls_segment_filename "hls/fileSequence%d.ts" \
          -use_localtime_mkdir 1 \

      Make sure the directory you are writing the segments to exists. Take a look at the available options for more information.

  4. ads1018

    Hey Simon, great post. I’m trying to implement an auth system so that when I stream a file, encrypted, over RTMP using ffmpeg you can only consume the the stream if they have a valid decryption key. Is this possible? If the decryption key is included in the generated playlist then *anyone* can consume it which isn’t ideal. Any thoughts, on how to achieve this? Ideally, I don’t have to use a crazy proprietary DRM solution with a license server.

    1. Simon Post author

      Even though the reference to the key is embedded in an HLS playlist, you can protect access to it. I’m going to assume that the key(s) and/or the playlist are served over HTTPS. You can use something like basic authentication, which requires a username and password, or use client certificates and enable TLS client authentication to restrict access. That’s not going to prevent an authorised user from accessing the key, but it will prevent an unauthorised user from doing so. Other than that, you’re going to have to resort to a DRM solution.

  5. Steve

    Hi Simon- With the help of your book, I have implemented HLS encryption successfully. The HLS encrypted chunks are stored on a protected server, and the embedded HLS player accesses the keys from the path in the playlist.m3u8 file. The keys are located on the same server that embeds the player, and viewers must be authenticated before accessing the player. To prevent just any site from accessing the key path, I have implemented CORS and only allowed the server where the player is embedded to access. Is there a better, more secure way to restrict access to the keys than CORS? Again, the player and the key store folder are both on the same site- both are off of the site root folder. Thanks for any advice you can give me.

    1. Simon Post author

      Here’s one idea. You could try including some sort of authentication token in the playlist URL, e.g. /playlist.m3u8?token=ABCDEFG. As the viewer is authenticated, you could tie the token to their identity.

      You would then check on the server if the token is valid or not. If it is valid, you could then set a (session) cookie. Any subsequent requests to the server, e.g. for the key(s), will include the Cookie header that you can then use to determine if the request is allowed or not.

      An alternative approach to using a cookie could be to generate the playlist dynamically and include the token in the path to the encryption key. There’s an example in the book of how to generate a playlist with PHP that you could use as a starting point.

      However, as I mentioned in a comment above, it won’t prevent an authorised user from accessing the key.


Leave a Reply