All Products
Search
Document Center

ApsaraVideo Media Processing:HLS encryption

Last Updated:Mar 05, 2024

The video encryption feature allows you to perform in-depth security processing on video content and prevent video data from being illegally acquired and transmitted. This feature is widely used to prevent video leaks and hotlinking in scenarios that require high security, such as online education and finance. ApsaraVideo Media Processing (MPS) supports two encryption methods: Alibaba Cloud proprietary cryptography and HTTP-Live-Streaming (HLS) encryption. This topic describes how HLS encryption works and how to use HLS encryption. This helps you ensure video security by using HLS encryption and smoothly play videos.

How it works

Terms

MPS uses the envelope encryption technology to encrypt videos. You can use Alibaba Cloud Key Management Service (KMS) to generate a data key (DK) and an enveloped data key (EDK). Then, you can use the DK to encrypt a video and store the encrypted video together with the EDK. If you want to play the video, the player uses a decryption service to obtain the DK and decrypt the video.

Note

HLS encryption requires you to preserve your DKs.

Term

Description

DK

A DK is also known as a plaintext key, which is used for video encryption.

EDK

An EDK is also known as a ciphertext data key, which is generated by using the envelope encryption technology. It is used to decrypt a DK and obtain the plaintext data key.

RAM

Resource Access Management (RAM) is a service provided by Alibaba Cloud. It allows you to manage user identities and resource access permissions. For more information, see What is RAM?

KMS

KMS is an end-to-end service platform for key management, data encryption, and secrets management. KMS provides simple, reliable, secure, and standard-compliant capabilities to encrypt and protect data and manage secrets. For more information, see What is KMS?

OSS

Object Storage Service (OSS) is a data storage service provided by Alibaba Cloud. Media files for MPS jobs are stored in OSS buckets. For more information, see What is OSS?

CDN

In the process of HLS encryption, Alibaba Cloud Content Delivery Network (CDN) dynamically modifies the decryption uniform resource identifier (URI) in the M3U8 file and returns the decryption URI to the player. For more information, see What is Alibaba Cloud CDN?.

Encryption process

  1. Activate the following services: MPS, OSS, RAM, KMS, and Alibaba Cloud CDN.

  2. Grant MPS the permissions to access KMS.

    Note

    This ensures that MPS can call the GenerateDataKey operation of KMS to generate DKs and EDKs during video encryption.

  3. Configure a CDN-accelerateddomain name for the OSS bucket that stores the output files of MPS jobs. Add a CNAME record and configure the origin host for the CDN-accelerated domain name.

  4. Create a workflow for video encryption and specify information such as the OSS bucket that stores output files and the key URI.

    The key URI specifies the endpoint of your services. The data about the key URI is contained in the M3U8 file generated by MPS after video encryption.

  5. Upload the video to be encrypted and specify the created workflow for the video.

  6. After the video is uploaded, MPS automatically triggers the workflow.

    Then, MPS calls the GenerateDataKey operation to generate a DK and an EDK, and uses the DK to encrypt the video. After the video is encrypted, MPS writes the data about the key URI and EDK to the M3U8 file.

  7. MPS stores the M3U8 file and the TS file in the OSS bucket that stores output files.

Decryption process

  1. Construct a token issuance service to generate the MtsHlsUriToken parameter.

    Important

    The token issuance service is used to generate the MtsHlsUriToken parameter.

  2. Call the Decrypt operation of KMS to construct a decryption service and return the DK to the player.

    Important

    After you call the Decrypt operation of KMS to obtain the Base64-encoded DK from KMS, decode the DK by using the Base64 algorithm and return the decoded DK to the player.

  3. Call the QueryMediaList operation of MPS to query the OSS URL of the M3U8 file, add the MtsHlsUriToken parameter to the OSS URL, and then return the OSS URL to the player.

  4. The player uses the MtsHlsUriToken parameter and the DK to request the streaming URL of the video from Alibaba Cloud CDN. Alibaba Cloud CDN modifies the M3U8 file and returns the key URI and EDK to the player. Then, the player decrypts and plays the video.

Code logic

In the processes of HLS encryption and decryption, you must implement the following code logic:

  1. Create a workflow for video encryption.

    Note

    Although you can create a workflow in the MPS console, we recommend that you create a workflow by using a server SDK.

  2. Construct a token issuance service to generate the MtsHlsUriToken parameter, which is used as the decryption token. Verify the decryption token. We recommend that you use each decryption token only once.

  3. Call the Decrypt operation of KMS to construct a decryption service. Decode the DK by using the Base64 algorithm and return the decoded DK to the player.

Preparations

Before you use HLS encryption in MPS, make the following preparations:

  1. Activate relevant Alibaba Cloud services, including MPS, OSS, KMS, RAM, and Alibaba Cloud CDN.

    If you have not activated these services, perform the following steps:

    1. Activate MPS. For more information, see Activate MPS.

    2. Activate OSS. For more information, see Activate OSS.

    3. Activate KMS. For more information, see Purchase a dedicated KMS instance.

    4. Activate Alibaba Cloud CDN. For more information, see Activate Alibaba Cloud CDN.

  2. Grant MPS the permissions to access KMS.

    1. Log on to the RAM console.

    2. In the left-side navigation pane, choose Permissions > Authorize. On the Permission page, click Grant Permission. The Authorize panel appears.

    3. In the Principal search box, enter AliyunMtsDefaultRole and select a role that is created by the system and can be used in MPS.

    4. In the search box of the Select Policy section, enter KMS. Select AliyunKMSFullAccess and click OK.

    Then, MPS is granted the permissions to access KMS. After MPS receives a video encryption request, MPS can call the Decrypt operation of KMS to obtain the DK.

  3. Configure a CDN-accelerated domain name for the OSS bucket that stores output files, and configure the origin host for the CDN-accelerated domain name. For more information, see Configure a domain name for CDN. If the CDN-accelerated domain name and the origin host are configured, skip this step.

    Note

    You can enter the public domain name of the OSS bucket, such as exampleBucket****.oss-cn-hangzhou.aliyuncs.com. You can obtain the public domain name in the OSS console. Alternatively, you can select the OSS bucket that stores output files and requires content delivery acceleration within the same Alibaba Cloud account. Internal domain names of OSS buckets are not supported.

Encrypt a video

To encrypt a video, perform the following steps:

  1. Create a workflow for video encryption.

    To create a workflow, you must use an Alibaba Cloud SDK, and add MPS dependencies. You can view the sample code of workflow creation based on the programming language that you use. For more information, see the following table.

    Important

    When you create a workflow, you must provide the key URI. During video encryption, MPS writes the key URI to the M3U8 file and stores the file in the OSS bucket that stores output files. An example of the key URI is example.aliyundoc.com.

    Programming language

    SDK

    Sample code

    Java

    SDK for Java

    Create a workflow for HLS encryption

    Python

    SDK for Python

    Create a workflow for HLS encryption

    PHP

    SDK for PHP

    Create a workflow for HLS encryption

  2. Upload a video to trigger the workflow. You can upload a video in the MPS console or OSS console.

    Note

    If you specify the created workflow for the video in the upload configuration, after the video is uploaded, MPS automatically triggers the workflow.

    After the video is encrypted, log on to the OSS console and view the M3U8 file in the OSS bucket that stores output files. The following sample code provides an example of the M3U8 file:

    #EXTM3U
         #EXT-X-VERSION:3
         #EXT-X-TARGETDURATION:5
         #EXT-X-MEDIA-SEQUENCE:0
         #EXT-X-KEY:METHOD=AES-128,URI="https://example.aliyundoc.com?Ciphertext=aabbccddeeff&MediaId=fbbf98691ea44b7c82dd75c5bc8b****"
         #EXTINF:4.127544,
         15029611683170-00001.ts
         #EXT-X-ENDLIST

    In this example, the key URI that you configure and the EDK are contained in the URI field.

Play an HLS-encrypted video

To play an HLS-encrypted video, perform the following steps:

  1. Construct a token issuance service.

    Note

    You must construct the token issuance service based on your encryption method to ensure a high security level.

  2. Construct a decryption service.

    Construct a local HTTP service to decrypt the video and obtain the decryption key. The following sample code provides examples on how to construct the decryption service in Java and Python.

    • Sample code in Java

      Dependencies required by the SDK for Java:

      Sample code for decryption by using the Base64 algorithm:

      Sample code

      import com.sun.net.httpserver.*;
      import com.sun.net.httpserver.spi.HttpServerProvider;
      
      import java.io.IOException;
      import java.io.OutputStream;
      import java.net.HttpURLConnection;
      import java.net.InetSocketAddress;
      
      /**
       * *****   Usage notes     ******
       * This sample code decodes the DK by using the Base64 algorithm.
       * The port number in the sample code is 8888. Make sure that this number is the same as that of the key URI.
       * If you need additional token verification, see the following sample code for decryption by using KMS.
       *
       * ***** Code logic ******
       * 1. Receive the decryption request and obtain the EDK.
       * 2. Decode the DK by using the Base64 algorithm and return the decoded DK.
       */
      public class Base64DecryptServer {
      
          public static void main(String[] args) throws IOException {
              Base64DecryptServer server = new Base64DecryptServer();
              server.startService();
          }
      
          public class Base64DecryptHandler implements HttpHandler {
              /**
               * Process the decryption request.
               * @param httpExchange
               * @throws IOException
               */
              public void handle(HttpExchange httpExchange) throws IOException {
                  String requestMethod = httpExchange.getRequestMethod();
                  if ("GET".equalsIgnoreCase(requestMethod)) {
                      // The decryption key must be the same as the encryption key.
                      byte[] key = "encryptionkey128".getBytes();
                      // Configure the headers.
                      setHeader(httpExchange, key);
                      // Return the DK that is decoded by using the Base64 algorithm.
                      OutputStream responseBody = httpExchange.getResponseBody();
                      System.out.println(new String(key));
                      responseBody.write(key);
                      responseBody.close();
                  }
              }
              private void setHeader(HttpExchange httpExchange, byte[] key) throws IOException {
                  Headers responseHeaders = httpExchange.getResponseHeaders();
                  responseHeaders.set("Access-Control-Allow-Origin", "*");
                  httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, key.length);
              }
          }
          /**
           * Start the service.
           * @throws IOException
           */
          private void startService() throws IOException {
              HttpServerProvider provider = HttpServerProvider.provider();
              // Configure a listener on port 8888, which can accept 30 requests at a time.
              HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8888), 30);
              httpserver.createContext("/", new Base64DecryptHandler());
              httpserver.start();
              System.out.println("base64 hls decrypt server started");
          }
      
      }

      Sample code for decryption by using KMS:

      Sample code

      import com.aliyun.mps.sdk.utils.InitClient;
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.http.ProtocolType;
      import com.aliyuncs.kms.model.v20160120.DecryptRequest;
      import com.aliyuncs.kms.model.v20160120.DecryptResponse;
      import com.sun.net.httpserver.*;
      import com.sun.net.httpserver.spi.HttpServerProvider;
      import org.apache.commons.codec.binary.Base64;
      
      import java.io.IOException;
      import java.io.OutputStream;
      import java.net.HttpURLConnection;
      import java.net.InetSocketAddress;
      import java.net.URI;
      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      
      /**
       * *****   Usage notes     ******
       * This sample code constructs the decryption service by using KMS with the M3U8 encryption and rewrite feature disabled. The MtsHlsUriToken parameter is not verified.
       * The port number in the sample code is 8888. Make sure that this number is the same as that of the key URI.
       *
       * ***** Code logic ******
       * 1. Receive the decryption request and obtain the EDK.
       * 2. Call the Decrypt operation of KMS to obtain the DK. 
       * 3. Decode the DK by using the Base64 algorithm and return the decoded DK.
       */
      public class HlsDecryptServerNoToken {
      
          private static DefaultAcsClient client;
          static {
              try{
                  client = InitClient.initMpsClient();
              }catch (Exception e){
                  e.printStackTrace();
              }
          }
      
          public static void main(String[] args) throws IOException {
              HlsDecryptServerNoToken server = new HlsDecryptServerNoToken();
              server.startService();
          }
      
          public class HlsDecryptHandler implements HttpHandler {
              public void handle(HttpExchange httpExchange) throws IOException {
                  String requestMethod = httpExchange.getRequestMethod();
                  if(requestMethod.equalsIgnoreCase("GET")){
                      // Obtain the EDK from the video URL.
                      String ciphertext = getCiphertext(httpExchange);
                      System.out.println(ciphertext);
                      if (null == ciphertext)
                          return;
                      // Decrypt the DK obtained from KMS and decode the DK by using the Base64 algorithm.
                      byte[] key = decrypt(ciphertext);
                      // Configure the header.
                      setHeader(httpExchange, key);
                      // Return the decoded DK.
                      OutputStream responseBody = httpExchange.getResponseBody();
                      responseBody.write(key);
                      responseBody.close();
                  }
              }
      
              private void setHeader(HttpExchange httpExchange, byte[] key) throws IOException {
                  Headers responseHeaders = httpExchange.getResponseHeaders();
                  responseHeaders.set("Access-Control-Allow-Origin", "*");
                  httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, key.length);
              }
      
              private byte[] decrypt(String ciphertext) {
                  DecryptRequest request = new DecryptRequest();
                  request.setCiphertextBlob(ciphertext);
                  request.setProtocol(ProtocolType.HTTPS);
                  try {
                      DecryptResponse response = client.getAcsResponse(request);
                      String plaintext = response.getPlaintext();
                      // Note: You must decode the DK by using the Base64 algorithm.
                      return Base64.decodeBase64(plaintext);
                  } catch (ClientException e) {
                      e.printStackTrace();
                      return null;
                  }
              }
              private String getCiphertext(HttpExchange httpExchange) {
                  URI uri = httpExchange.getRequestURI();
                  String queryString = uri.getQuery();
                  String pattern = "Ciphertext=(\\w*)";
                  Pattern r = Pattern.compile(pattern);
                  Matcher m = r.matcher(queryString);
                  if (m.find())
                      return m.group(1);
                  else {
                      System.out.println("Not Found Ciphertext");
                      return null;
                  }
              }
          }
      
          /**
           * Start the service.
           *
           * @throws IOException
           */
          private void startService() throws IOException {
              HttpServerProvider provider = HttpServerProvider.provider();
              // Configure a listener on port 8888, which can accept 30 requests at a time. You can change the port based on your business requirements.
              HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8888), 30);
              httpserver.createContext("/", new HlsDecryptHandler());
              httpserver.start();
              System.out.println("no token hls decrypt server started");
          }
      
      }
    • Sample code in Python

      Dependencies required by the SDK for Python:

      • pip install aliyun-python-sdk-core

      • pip install aliyun-python-sdk-kms

      • pip install aliyun-python-sdk-mts

      Sample code in Python:

      Sample code

      
      # -*- coding: UTF-8 -*- 
      from BaseHTTPServer import BaseHTTPRequestHandler
      from aliyunsdkcore.client import AcsClient
      from aliyunsdkkms.request.v20160120 import DecryptRequest
      import cgi
      import json
      import base64
      import urlparse
      client = AcsClient("","","");
      class AuthorizationHandler(BaseHTTPRequestHandler):
      def do_GET(self):
      self.check()
      self.set_header()
      cipertext = self.get_cihpertext()
      plaintext = self.decrypt_cihpertext(cipertext)
      print plaintext
      key = base64.b64decode(plaintext)
      print key
      self.wfile.write(key)
      def do_POST(self):
      pass
      def check(self):
      #check MtsHlsUriToken, etc.
      pass
      def set_header(self):
      self.send_response(200)
      #cors
      self.send_header('Access-Control-Allow-Origin', '*')
      self.end_headers()
      def get_cihpertext(self):
      path = urlparse.urlparse(self.path)
      query = urlparse.parse_qs(path.query)
      return query.get('Ciphertext')[0]
      def decrypt_cihpertext(self, cipertext):
      request = DecryptRequest.DecryptRequest()
      request.set_CiphertextBlob(cipertext)
      response = client.do_action_with_exception(request)
      jsonResp = json.loads(response)
      return jsonResp["Plaintext"]
      if __name__ == '__main__':
      # Start a simple server, and loop forever
      from BaseHTTPServer import HTTPServer
      print "Starting server, use  to stop"
      server = HTTPServer(('127.0.0.1', 8888), AuthorizationHandler)
      server.serve_forever()
  3. Call the QueryMediaList operation of MPS to query the streaming URL of the video.

    You can call the operation in OpenAPI Explorer or by integrating an SDK.

  4. Play the encrypted video.

    You can use ApsaraVideo Player or a third-party player to play the encrypted video.

    • If you use a third-party player, specify the playback logic.

    • If you use ApsaraVideo Player, obtain the security token and authentication information as required before the video is played. For more information, see Play videos.

    You can also use an online player to test the playback of the video encrypted by HLS encryption.

    For example, you can use the ApsaraVideo Player diagnostics tool. When you use this tool, enter the streaming URL of the video in the Source field and click Play.

    Note

    On the browser debugging page, you can see that the player sends a request to the authentication server, obtains the decryption key, and then decrypts and plays the video.

    The following procedure describes how ApsaraVideo Player tests the playback:

    • After ApsaraVideo Player receives the streaming URL, it replaces the domain name of the OSS bucket with a CDN-accelerated domain name. Then, ApsaraVideo Player adds the MtsHlsUriToken parameter, which is used as the decryption token, to the CDN-accelerated domain name, and sends a request to Alibaba Cloud CDN for a modified streaming URL. Sample request: https://example.aliyundoc.com/test_01.m3u8?MediaId=fbbf98691ea44b7c82dd75c5bc8b****&MtsHlsUriToken=<Token>.

      Important

      If you use ApsaraVideo Player, the MtsHlsUriToken parameter is automatically added. If you use other players, you must manually add the MtsHlsUriToken parameter.

    • After Alibaba Cloud CDN receives the request, it dynamically modifies the key URI in the M3U8 file and returns the modified streaming URL to the player. For example, if the original streaming URL is https://example.aliyundoc.com?Ciphertext=aabbccddeeff&MediaId=fbbf98691ea44b7c82dd75c5bc8b****, the returned streaming URL is https://example.aliyundoc.com?Ciphertext=aabbccddeeff&MediaId=fbbf98691ea44b7c82dd75c5bc8b****&MtsHlsUriToken=<Token>.

    • The player parses and accesses the URI in the EXT-X-KEY tag of the M3U8 file to obtain the decryption key. Call the Decrypt operation of KMS, decode the obtained DK by using the Base64 algorithm, and then return the decoded DK to the player. The player uses the DK to decrypt the TS file and plays the video.

References

Alibaba Cloud proprietary cryptography