Export (0) Print
Expand All

Using Static Encryption to Protect HLSv3 with AES-128

Updated: August 13, 2014

If you want to encrypt your HLS with AES-128, you have a choice of using dynamic encryption (the recommended option) or static encryption. The following blog discusses both options Dynamic Encryption vs. Static Encryption. If you decide to use dynamic encryption, see Using AES-128 Dynamic Encryption and Key Delivery Service.

Note, when using static encryption, AES-128 encryption can only be applied to HLS.

With static encryption, you would typically perform the following steps. If you are starting with adaptive bitrate Smooth Streaming files, skip to step 4.

  1. Upload an input file (called a mezzanine file). For example, H.264, MP4, or WMV (for the list of supported formats see Formats Supported by the Media Services Encoder).

  2. Encode your mezzanine file into a set of adaptive bitrate MP4s.

  3. Package your adaptive bitrate MP4s to Smooth Streaming.

  4. Package Smooth Streaming into HTTP Live Streaming (HLS) encrypted with Advanced Encryption Standard (AES).

  5. Create an on demand locator that links to an asset on the server. Then, build the full URL. In the case of HTTP Live Streaming (HLS): {media services account name}.origin.mediaservices.net/{locator ID}/{filename}.ism/Manifest(format=m3u8-aapl).

The example in this topic encodes a mezzanine file (in this case MP4) into multibitrate MP4 files and then packages MP4s into Smooth Streaming. It then packages Smooth Streaming into HTTP Live Streaming (HLS) encrypted with Advanced Encryption Standard (AES) 128-bit stream encryption.

noteNote
In order to convert your content into HLS, you must first convert/encode your content into Smooth Streaming.

You can download the following project that contains the code shown in this example and much more: Media Services Content Protection.

  1. The following topics show how to setup for Media Services development.

    Setup for Development with the Media Services SDK for .NET

    Note that code in this topic uses Azure Media Services .NET SDK Extensions.  The Media Services .NET SDK Extensions is a set of extension methods and helper functions that simplify your code and make it easier to develop with Media Services.

  2. Connect to Media Services Using the Media Services SDK

  1. Overwrite the code in your Program.cs file with the code shown in the Example section.

    Make sure to update the following code to point to the folder where your input MP4 file is located.

    And also to where your MediaPackager_MP4ToSmooth.xml and MediaPackager_SmoothToHLS.xml configuration files are located. You can find the definition for these files in the Task Preset for Azure Media Packager topic.

    ImportantImportant
    For the HLS to get encrypted with AES make sure to set the following properties in your MediaPackager_SmoothToHLS.xml file: set the encrypt property to true, set the key value, and the keyuri value to point to your authentication\authorization server.

    Media Services will create a key file and place it in the asset container. You should copy the /asset-containerguid/*.key file to your server (or create your own key file) and then delete the *.key file from the asset container.

    private static readonly string _mediaFiles = Path.GetFullPath(@"../..\Media");
    
    private static readonly string _singleMP4File =
         Path.Combine(_mediaFiles, @"SingleMP4\BigBuckBunny.mp4");
    
    // XML Configruation files path.
    private static readonly string _configurationXMLFiles = @"../..\Configurations\";
    
    
  2. Build and run your program.

  3. Use a player that can playback the HLS content to test the streaming URL. For example, the 3ivx HLS player player.

Example

The example does the following:

  1. Ingests a single MP4 file.

  2. Encodes MP4 into multibitrate MP4s using the "H264 Adaptive Bitrate MP4 Set 720p",encoder preset. Then, packages multibitrate MP4s into Smooth Streaming. The MediaPackager_MP4ToSmooth.xml and MediaPackager_SmoothToHLS.xml configurations are used for these packaging tasks.

  3. Packages Smooth Streaming into HLS encrypted with AES. The MediaPackager_SmoothToHLS.xml configuration is used for this packaging task.

  4. Gets the streaming URL.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MediaServices.Client;
using System.Xml.Linq;

namespace MediaServicesContentProtection
{
    class Program
    {
        // Paths to support files (within the above base path). You can use 
        // the provided sample media files from the "SupportFiles" folder, or 
        // provide paths to your own media files below to run these samples.

        private static readonly string _mediaFiles =
            Path.GetFullPath(@"../..\Media");
        
        private static readonly string _singleMP4File =
            Path.Combine(_mediaFiles, @"SingleMP4\BigBuckBunny.mp4");

        // XML Configruation files path.
        private static readonly string _configurationXMLFiles = @"../..\Configurations\";

        private static MediaServicesCredentials _cachedCredentials = null;
        private static CloudMediaContext _context = null;

        // Media Services account information.
        private static readonly string _mediaServicesAccountName = 
            ConfigurationManager.AppSettings["MediaServiceAccountName"];
        private static readonly string _mediaServicesAccountKey = 
            ConfigurationManager.AppSettings["MediaServiceAccountKey"];

        static void Main(string[] args)
        {
            // Create and cache the Media Services credentials in a static class variable.
            _cachedCredentials = new MediaServicesCredentials(
                            _mediaServicesAccountName, 
                            _mediaServicesAccountKey);
            // Use the cached credentials to create CloudMediaContext.
            _context = new CloudMediaContext(_cachedCredentials);

            // Encoding and encrypting assets //////////////////////

            // Load an MP4 file.
            IAsset asset = IngestSingleMP4File(_singleMP4File, AssetCreationOptions.None);

            // Encode an MP4 file to a set of multibitrate MP4s.
            // Then, package a set of MP4s to clear Smooth Streaming.
            IAsset clearSmoothStreamAsset = ConvertMP4ToMultibitrateMP4sToSmoothStreaming(asset);

            // Create HLS encrypted with AES.
            IAsset HLSEncryptedWithAESAsset = CreateHLSEncryptedWithAES(clearSmoothStreamAsset);

            // You can use the following player to test the HLS with AES stream.
            // http://apps.microsoft.com/windows/en-us/app/3ivx-hls-player/f79ce7d0-2993-4658-bc4e-83dc182a0614 
            string hlsWithAESURL = HLSEncryptedWithAESAsset.GetHlsUri().ToString();
            Console.WriteLine("HLS with AES URL:");
            Console.WriteLine(hlsWithAESURL);
        }


        /// <summary>
        /// Creates a job with 2 tasks: 
        /// 1 task - encodes a single MP4 to multibitrate MP4s,
        /// 2 task - packages MP4s to Smooth Streaming.
        /// </summary>
        /// <returns>The output asset.</returns>
        public static IAsset ConvertMP4ToMultibitrateMP4sToSmoothStreaming(IAsset asset)
        {
            // Create a new job.
            IJob job = _context.Jobs.Create("Convert MP4 to Smooth Streaming.");

            // Add task 1 - Encode single MP4 into multibitrate MP4s.
            IAsset MP4sAsset = EncodeSingleMP4IntoMultibitrateMP4sTask(job, asset);
            // Add task 2 - Package a multibitrate MP4 set to Clear Smooth Streaming.
            IAsset packagedAsset = PackageMP4ToSmoothStreamingTask(job, MP4sAsset);

            // Submit the job and wait until it is completed.
            job.Submit();
            job = job.StartExecutionProgressTask(
                j =>
                {
                    Console.WriteLine("Job state: {0}", j.State);
                    Console.WriteLine("Job progress: {0:0.##}%", j.GetOverallProgress());
                },
                CancellationToken.None).Result;

            // Get the output asset that contains Smooth Streaming.
            return job.OutputMediaAssets[1];
        }

        /// <summary>
        /// Encrypts an HLS with AES-128.
        /// </summary>
        /// <param name="clearSmoothAsset">Asset that contains clear Smooth Streaming.</param>
        /// <returns>The output asset.</returns>
        public static IAsset CreateHLSEncryptedWithAES(IAsset clearSmoothStreamAsset)
        {
            IJob job = _context.Jobs.Create("Encrypt to HLS with AES.");

            // Add task 1 - Package clear Smooth Streaming to HLS with AES.
            PackageSmoothStreamToHLS(job, clearSmoothStreamAsset);

            // Submit the job and wait until it is completed.
            job.Submit();
            job = job.StartExecutionProgressTask(
                j =>
                {
                    Console.WriteLine("Job state: {0}", j.State);
                    Console.WriteLine("Job progress: {0:0.##}%", j.GetOverallProgress());
                },
                CancellationToken.None).Result;

            // The OutputMediaAssets[0] contains the desired asset.
            _context.Locators.Create(
                LocatorType.OnDemandOrigin,
                job.OutputMediaAssets[0],
                AccessPermissions.Read,
                TimeSpan.FromDays(30));

            return job.OutputMediaAssets[0];
        }

        /// <summary>
        /// Uploads a single file.
        /// </summary>
        /// <param name="fileDir">The location of the files.</param>
        /// <param name="assetCreationOptions">
        ///  You can specify the following encryption options for the AssetCreationOptions.
        ///      None:  no encryption.  
        ///      StorageEncrypted: storage encryption. Encrypts a clear input file 
        ///        before it is uploaded to Azure storage. 
        ///      CommonEncryptionProtected: for Common Encryption Protected (CENC) files. 
        ///        For example, a set of files that are already PlayReady encrypted. 
        ///      EnvelopeEncryptionProtected: for HLS with AES encryption files.
        ///        NOTE: The files must have been encoded and encrypted by Transform Manager. 
        ///     </param>
        /// <returns>Returns an asset that contains a single file.</returns>
        /// </summary>
        /// <returns></returns>
        private static IAsset IngestSingleMP4File(string fileDir, AssetCreationOptions assetCreationOptions)
        {
            // Use the SDK extension method to create a new asset by 
            // uploading a mezzanine file from a local path.
            IAsset asset = _context.Assets.CreateFromFile(
                fileDir,
                assetCreationOptions,
                (af, p) =>
                {
                    Console.WriteLine("Uploading '{0}' - Progress: {1:0.##}%", af.Name, p.Progress);
                });
 
            return asset;
        }

        /// <summary>
        /// Creates a task to encode to Adaptive Bitrate. 
        /// Adds the new task to a job.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The input asset.</param>
        /// <returns>The output asset.</returns>
        private static IAsset EncodeSingleMP4IntoMultibitrateMP4sTask(IJob job, IAsset asset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Encoder.
            IMediaProcessor encoder = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.AzureMediaEncoder);

            ITask adpativeBitrateTask = job.Tasks.AddNew("MP4 to Adaptive Bitrate Task",
               encoder,
               "H264 Adaptive Bitrate MP4 Set 720p",
               TaskOptions.None);

            // Specify the input Asset
            adpativeBitrateTask.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job. 
            // This output is specified as AssetCreationOptions.None, which 
            // means the output asset is in the clear (unencrypted).
            IAsset abrAsset = adpativeBitrateTask.OutputAssets.AddNew("Multibitrate MP4s", 
                                    AssetCreationOptions.None);

            return abrAsset;
        }

        /// <summary>
        /// Creates a task to convert the MP4 file(s) to a Smooth Streaming asset.
        /// Adds the new task to a job.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The input asset.</param>
        /// <returns>The output asset.</returns>
        private static IAsset PackageMP4ToSmoothStreamingTask(IJob job, IAsset asset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Packager.
            IMediaProcessor packager = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.WindowsAzureMediaPackager);

            // Azure Media Packager does not accept string presets, so load xml configuration
            string smoothConfig = File.ReadAllText(Path.Combine(
                        _configurationXMLFiles, 
                        "MediaPackager_MP4toSmooth.xml"));

            // Create a new Task to convert adaptive bitrate to Smooth Streaming.
            ITask smoothStreamingTask = job.Tasks.AddNew("MP4 to Smooth Task",
               packager,
               smoothConfig,
               TaskOptions.None);

            // Specify the input Asset, which is the output Asset from the first task
            smoothStreamingTask.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job. 
            // This output is specified as AssetCreationOptions.None, which 
            // means the output asset is in the clear (unencrypted).
            IAsset smoothOutputAsset = 
                smoothStreamingTask.OutputAssets.AddNew("Clear Smooth Streaming", 
                    AssetCreationOptions.None);

            return smoothOutputAsset;
        }

        /// <summary>
        /// Converts Smooth Streaming to HLS.
        /// </summary>
        /// <param name="job">The job to which to add the new task.</param>
        /// <param name="asset">The Smooth Streaming asset.</param>
        /// <returns>The asset that was packaged to HLS.</returns>
        private static IAsset PackageSmoothStreamToHLS(IJob job, IAsset smoothStreamAsset)
        {
            // Get the SDK extension method to  get a reference to the Azure Media Packager.
            IMediaProcessor processor = _context.MediaProcessors.GetLatestMediaProcessorByName(
                MediaProcessorNames.WindowsAzureMediaPackager);

            // Read the configuration data into a string. 
            // For the HLS to get encrypted with AES make sure to set the
            // encrypt configuration property to true.
            //
            // In production, it is recommended to do the following:
            //    Set a Key url for your authn/authz server.
            //    Copy the /asset-containerguid/*.key file to your server (or craft a key file for yourself).
            //    Delete *.key from the asset container.
            //
            string configuration = File.ReadAllText(Path.Combine(_configurationXMLFiles, @"MediaPackager_SmoothToHLS.xml"));

            // Create a task with the encoding details, using a configuration file.
            ITask task = job.Tasks.AddNew("My Smooth Streaming to HLS Task",
               processor,
               configuration,
               TaskOptions.ProtectedConfiguration);

            // Specify the input asset to be encoded.
            task.InputAssets.Add(smoothStreamAsset);

            // Add an output asset to contain the results of the job. 
            IAsset outputAsset = 
                task.OutputAssets.AddNew("HLS asset", AssetCreationOptions.None);


            return outputAsset;
        }
    }
}

See Also

Show:
© 2015 Microsoft