Azure Media - Implement Media Content Encryption

Hey Guys! I am writing this article on the encryption of the video using Azure Media Service. I am going to explain this topic with a real scenario that I faced in my project.

I was working on one of the projects in which the following requirement was raised by the client:

The published URL generated by Azure Media Service shouldn’t be accessible publicly to all of the users. It should be accessed only by authorized users. There should be some token provided to the authorized user by using which the user can see the video.

I researched various approaches for the above requirement and finally, got the following solution.

Solution

Azure Media Services provides the feature of content protection. By using this feature, we can dynamically encrypt the video using AES (Advanced Encryption Standard) or any other technique of DRM (Digital Rights Management) system. Some Major DRM systems are -Microsoft PlayReady, Google WideDivine, and Apple FairPlay.

In this article, I am going to talk about the encryption of video using AES (Advanced Encryption Standard).

Steps for implementing content protection of video using AES.

Prerequisites

  1. Azure Subscription.
  2. Configured Azure Media Services.

Step 1

Configure the content protection policy for Azure Media Services. 

 

 

Step 2

Upload MP4 video using the Asset tab in configured Azure Media Services. 
 
 

Step 3

Encode the video using the Encode option. 

 

Step 4

Get the encoded asset from Azure Media Services using the following code. 

  1. private static CloudMediaContext _context = null;  
  2. static string tenantDomain = ConfigurationManager.AppSettings["TenantDomain"];  
  3. static string clientId = ConfigurationManager.AppSettings["ClientId"];  
  4. static string clientKey = ConfigurationManager.AppSettings["ClientKey"];  
  5. static string apiServer = ConfigurationManager.AppSettings["ApiServer"];  
  6. static string assetId = "nb:cid:UUID:XXXX-XXXX-XXXX-XXXX-XXXXXXX“;   
  7.    
  8. public IAsset GetAssetByid(string id)  
  9. {  
  10. var tokenCredentials = new AzureAdTokenCredentials(tenantDomain, new AzureAdClientSymmetricKey(clientId, clientKey), AzureEnvironments.AzureCloudEnvironment);  
  11.          var tokenProvider = new AzureAdTokenProvider(tokenCredentials);  
  12.          _context = new CloudMediaContext(new Uri(apiServer), tokenProvider);  
  13.                 var assetInstance =  
  14.                 from a in _context.Assets  
  15.                 where a.Id == assetId  
  16.                 select a;  
  17.   
  18.          IAsset asset = assetInstance.FirstOrDefault();  
  19. }  

Step 5

Add the code for creating a content key and attach it to the asset.

The content key is used to secure the asset. It provides a key using which the encoded asset is going to be encrypted. The following code can be used to create the content key. 

  1. public static IContentKey CreateContentKeys(IAsset asset)  
  2.  {  
  3.       Guid keyId = Guid.NewGuid();  
  4.       byte[] contentKey = GetRandomBuffer(16);  
  5.       if(asset.ContentKeys.Count>0)  
  6.       {  
  7.         return asset.ContentKeys[0];  
  8.       }  
  9.       IContentKey key = _context.ContentKeys.Create(keyId, contentKey, "ContentKey",  
  10.                               ContentKeyType.EnvelopeEncryption);  
  11.       asset.ContentKeys.Add(key);  
  12.       return key;  
  13.     }  
  14. static private byte[] GetRandomBuffer(int size)  
  15.  {  
  16.       byte[] randomBytes = new byte[size];  
  17.       using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())  
  18.       {  
  19.         rng.GetBytes(randomBytes);  
  20.       }  
  21.      return randomBytes;  
  22.     }  

Step 6

Create a token restriction authorization policy and attach to the content key.

  1. static public string AddTokenRestrictedAuthorizationPolicy(IContentKey contentKey)  
  2.     {  
  3.       string tokenTemplateString = null;  
  4.       if (!string.IsNullOrEmpty(contentKey.AuthorizationPolicyId))  
  5.       {  
  6.         tokenTemplateString = GetTemplateString(contentKey);  
  7.         return tokenTemplateString;  
  8.       }  
  9.       else  
  10.       {  
  11.         tokenTemplateString = GenerateTokenRequirements();  
  12.       }  
  13.         
  14.       IContentKeyAuthorizationPolicy policy = _context.  
  15.                               ContentKeyAuthorizationPolicies.  
  16.                               CreateAsync("HLS token restricted authorization policy").Result;  
  17.   
  18.       List<ContentKeyAuthorizationPolicyRestriction> restrictions =  
  19.               new List<ContentKeyAuthorizationPolicyRestriction>();  
  20.   
  21.       ContentKeyAuthorizationPolicyRestriction restriction =  
  22.               new ContentKeyAuthorizationPolicyRestriction  
  23.               {  
  24.                 Name = "Token Authorization Policy",  
  25.                 KeyRestrictionType = (int)ContentKeyRestrictionType.TokenRestricted,  
  26.                 Requirements = tokenTemplateString  
  27.               };  
  28.   
  29.       restrictions.Add(restriction);  
  30.       IContentKeyAuthorizationPolicyOption policyOption =  
  31.           _context.ContentKeyAuthorizationPolicyOptions.Create(  
  32.               "Token option for HLS",  
  33.               ContentKeyDeliveryType.BaselineHttp,  
  34.               restrictions,  
  35.               null  );  
  36.   
  37.       policy.Options.Add(policyOption);  
  38.       // Add ContentKeyAutorizationPolicy to ContentKey  
  39.       contentKey.AuthorizationPolicyId = policy.Id;  
  40.       contentKey = contentKey.UpdateAsync().Result;  
  41.       Console.WriteLine("Adding Key to Asset: Key ID is " + contentKey.Id);  
  42.       return tokenTemplateString;  
  43.     }  
  44.   
  45. public static string GetTemplateString(IContentKey key)  
  46.     {  
  47.       var authorizationPolicy = _context.ContentKeyAuthorizationPolicies.Where(x => x.Id == key.AuthorizationPolicyId).FirstOrDefault();  
  48.       string templatestring = authorizationPolicy.Options.FirstOrDefault().Restrictions.FirstOrDefault().Requirements;  
  49.       return templatestring;  
  50.     }     
  51.    public static string GetAuthorizationToken(IContentKey key,string tokenTemplateString)  
  52.     {   
  53.       if (tokenRestriction && !String.IsNullOrEmpty(tokenTemplateString))  
  54.       {  
  55.         TokenRestrictionTemplate tokenTemplate =  
  56.             TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);  
  57. Guid rawkey = EncryptionUtils.GetKeyIdAsGuid(key.Id);  
  58.   
  59.         string authorizationToken = TokenRestrictionTemplateSerializer.GenerateTestToken(tokenTemplate, null, rawkey, DateTime.UtcNow.AddDays(365));  
  60.           
  61.         Console.WriteLine("The authorization token is:\nBearer {0}", authorizationToken);  
  62.         Console.WriteLine();  
  63.   
  64.         return authorizationToken;  
  65.       }  
  66.       return string.Empty;  
  67.     }  

Step 7

Create an Asset Delivery Policy for the asset.

  1. static public void CreateAssetDeliveryPolicy(IAsset asset, IContentKey key)  
  2.     {  
  3.       if (asset.DeliveryPolicies.Count > 0)  
  4.         return;  
  5.       Uri keyAcquisitionUri = key.GetKeyDeliveryUrl(ContentKeyDeliveryType.BaselineHttp);  
  6.   
  7.       string envelopeEncryptionIV = Convert.ToBase64String(GetRandomBuffer(16));  
  8.   
  9.       // The following policy configuration specifies:   
  10.       //   key url that will have KID=<Guid> appended to the envelope and  
  11.       //   the Initialization Vector (IV) to use for the envelope encryption.  
  12.       Dictionary<AssetDeliveryPolicyConfigurationKey, string> assetDeliveryPolicyConfiguration =  
  13.           new Dictionary<AssetDeliveryPolicyConfigurationKey, string>  
  14.       {  
  15.                         {  
  16. AssetDeliveryPolicyConfigurationKey.EnvelopeKeyAcquisitionUrl, keyAcquisitionUri.ToString()}  
  17.       };  
  18.   
  19.       IAssetDeliveryPolicy assetDeliveryPolicy =  
  20.           _context.AssetDeliveryPolicies.Create(  
  21.                       "AssetDeliveryPolicy",  
  22.                       AssetDeliveryPolicyType.DynamicEnvelopeEncryption,  
  23.                       AssetDeliveryProtocol.SmoothStreaming | AssetDeliveryProtocol.HLS | AssetDeliveryProtocol.Dash,  
  24.                       assetDeliveryPolicyConfiguration);  
  25.   
  26.       // Add AssetDelivery Policy to the asset  
  27.       asset.DeliveryPolicies.Add(assetDeliveryPolicy);  
  28.       Console.WriteLine();  
  29.       Console.WriteLine("Adding Asset Delivery Policy: " +  
  30.           assetDeliveryPolicy.AssetDeliveryPolicyType);  
  31.     } 
Step 8
 
Set Up Origin Locator to get the publish URL of the asset.
  1. static public string GetStreamingOriginLocator(IAsset asset)  
  2.     {        
  3.       // Get a reference to the streaming manifest file from the    
  4.       // collection of files in the asset.   
  5.   
  6.       var assetFile = asset.AssetFiles.Where(f => f.Name.ToLower().  
  7.                                   EndsWith(".ism")).  
  8.                                   FirstOrDefault();  
  9.   
  10.       IAccessPolicy policy = _context.AccessPolicies.Create("Streaming policy",  
  11.             TimeSpan.FromDays(30),  
  12.             AccessPermissions.Read);  
  13.   
  14.       ILocator originLocator = _context.Locators.CreateLocator(LocatorType.OnDemandOrigin, asset,  
  15.           policy,  
  16.           DateTime.UtcNow.AddMinutes(-5));  
  17.         
  18.       return originLocator.Path + assetFile.Name;  
  19.     }  
Step 9 
 
Now we can get the AES key which can be used to play the video in Azure Media Player
  1. public static string GetAuthorizationToken(IContentKey key,string tokenTemplateString)  
  2.     {   
  3.       if (tokenRestriction && !String.IsNullOrEmpty(tokenTemplateString))  
  4.       {  
  5.         TokenRestrictionTemplate tokenTemplate =  
  6.             TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);  
  7.   
  8.        Guid rawkey = EncryptionUtils.GetKeyIdAsGuid(key.Id);  
  9.           
  10.        string authorizationToken = TokenRestrictionTemplateSerializer.  
  11.        GenerateTestToken(tokenTemplate, null, rawkey, DateTime.UtcNow.AddDays(365));  
  12.           
  13.         Console.WriteLine("The authorization token is:\nBearer {0}", authorizationToken);  
  14.         Console.WriteLine();  
  15.   
  16.         return authorizationToken;  
  17.       }  
  18.   
  19.       return string.Empty;  
  20.     }  
Step 10
 
Now we can test the video in Azure Media Player. We have to provide published URL and the encryption key in AMP. 
 
That's it. Your video file is encrypted now.