All Products
Search
Document Center

ApsaraVideo VOD:HLS encryption

Last Updated:May 28, 2025

HLS encryption uses AES-128 to encrypt videos. This method works with all HLS-compatible players and requires key management and token services for access control. HLS encryption is commonly used in high-security-demand fields such as online education platforms and exclusive content streaming. This topic describes how to implement HLS encryption for video delivery and decryption for video playback.

Working principle

ApsaraVideo VOD employs the envelope encryption technology, where service providers generate a data key (DK) and an enveloped data key (EDK) through Alibaba Cloud Key Management Service (KMS). The DK encrypts the video content, while the EDK is stored alongside the encrypted video. During playback, the decryption service retrieves the DK to decrypt the video.

If you want to validate the decryption URL, you can enable M3U8 encryption and rewrite (by default, MtsHlsUriToken is rewritten). This adds an extra layer of encryption to HLS data access.

Prerequisites

  • Your Alibaba Cloud account has sufficient balance. HLS encryption is a free service, but since encryption requires video transcoding, there will be service fees for the transcoding operations. For pricing details, see Media transcoding.

  • ApsaraVideo VOD is activated. For more information, see Activate ApsaraVideo VOD.

  • ApsaraVideo VOD is authorized to access KMS. You can authorize ApsaraVideo VOD to access KMS on the Cloud Resource Access Authorization page.

  • An accelerated domain is added to ApsaraVideo VOD. For more information, see Add a domain name for CDN.

  • The ApsaraVideo VOD SDK is integrated. In this topic, ApsaraVideo VOD SDK for Java is used as an example.

Concepts

Concept

Description

RAM

Resource Access Management (RAM) is a service from Alibaba Cloud that helps you manage user identities and control access to resources. For more information, see What is RAM?

KMS

KMS is a comprehensive platform for key management, data encryption, and secret management. It offers simple, reliable, and secure solutions that ensure data is encrypted, protected, and compliant with industry standards. For more information, see What is KMS?

DK

A DK is a plaintext key used to encrypt data. For more information, see Terms.

EDK

An EDK is a ciphertext data key created by using envelope encryption. For more information, see Terms.

Encryption and decryption process

Upload and encryption

视频安全-HLS标准加密3

Decryption and playback

(Recommended) M3U8 encryption and rewrite enabled

视频安全-HLS标准加密6..png

M3U8 encryption and rewrite disabled

视频安全-HLS标准加密2

Encrypt a video

  1. Upload your video and receive a callback.

    To ensure that videos supporting HLS encryption are not automatically transcoded, you must use the system's built-in No Transcoding template group when uploading them to ApsaraVideo VOD. This prevents automatic transcoding from being triggered during the upload process.

    1. Upload the video by using the ApsaraVideo VOD console or API.

    2. Configure event notifications. When you receive the FileUploadComplete callback message, it means the video has been successfully uploaded to ApsaraVideo VOD.

  2. Set up a key management service.

    1. Create a service key.

      The service key is the main encryption key in KMS and must be used to generate HLS encryption keys. Failure to create a service key will result in errors when you call the GenerateKMSDataKey operation.

      1. In the upper-left corner of the page, select the region in which you want to create a service key.

        Note

        The service key must be created in the same region as the origin server where your video is stored. For example, if your video is stored in China (Shanghai), the service key must also be created in China (Shanghai).

        标准加密-服务地域

      2. Log on to the ApsaraVideo VOD console. In the left-side navigation pane, choose Configuration Management > Media Processing > HLS Encryption.

      3. On the HLS Encryption page, click Create Service Key.

        After the service key is created, the system prompts The service key is created. You can view the service key in the Key Information section.

        Note

        If you have been notified that the service key has been successfully created but still cannot view the key, it may be due to a missing service-linked role. You can reauthorize to restore the role and then refresh the page to view the service key.

    2. Generate a DK.

      To generate a DK and an EDK, call the GenerateKMSDataKey operation without the need for any input parameters. Upon success, CiphertextBlob in the response provides the AES_128 formatted EDK which must be cached for HLS encryption and transcoding, while Plaintext in the response contains the DK.

  3. Create a transcoding template group for HLS encryption.

    During the HLS encryption process, you need two transcoding template groups: the built-in No Transcoding template group and a custom transcoding template group. Here's how to create a custom transcoding template group for HLS encryption:

    1. Log on to the ApsaraVideo VOD console. In the left-side navigation pane, choose Configuration Management > Media Processing > Transcoding Template Groups.

    2. On the Transcoding Template Groups page, click Create Transcoding Template Group.

      In the Basic Parameters section, set Encapsulation Format to hls. In the Advanced Parameters section, turn on Video Encryption and set Encryption Method to Alibaba Cloud Proprietary Cryptography. As for other parameters, configure them based on your actual needs. For information about parameter description, see Transcoding templates.视频安全-HLS加密-控制台

    3. After creating the transcoding template group, find its ID on the Transcoding Template Groups page. Save this ID, as you will need it later for HLS encryption and transcoding.视频安全-HLS加密-控制台1

  4. Initiate an HLS encryption and transcoding request.

    1. Call the SubmitTranscodeJobs operation to start HLS encryption and transcoding.

      Sample code in Java

      The following table describes the parameters in the sample code. You can modify them based on your business needs.

      Parameter

      Description

      request.setTemplateGroupId("")

      The ID of the transcoding template group created in Step 3.

      request.setVideoId("")

      The ID of the video uploaded in Step 1.

      encryptConfig.put("CipherText","")

      The value of CiphertextBlob returned in Step 2.

      encryptConfig.put("DecryptKeyUri","")

      The key URI. The URI consists of the IP address of the decryption service and the value of CiphertextBlob. If local port 8099 is used, the key URI is http://172.16.0.1:8099?CipherText=The value of CiphertextBlob

      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.profile.DefaultProfile;
      import com.aliyuncs.vod.model.v20170321.SubmitTranscodeJobsRequest;
      import com.aliyuncs.vod.model.v20170321.SubmitTranscodeJobsResponse;
      
      public class SubmitTranscodeJobs {
      
          // The AccessKey pair of an Alibaba Cloud account has permissions to call all API operations. We recommend that you use the AccessKey pair of a RAM user to call API operations or perform routine O&M. 
          // We recommend that you do not hardcode your AccessKey pair (AccessKey ID and AccessKey secret) in your project code. Otherwise, the AccessKey pair may be leaked and the security of all resources within your account may be compromised. 
          // In this example, ApsaraVideo VOD reads the AccessKey pair from environment variables to implement identity verification for API access. Before you run the sample code, configure the following environment variables: ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET. 
          private static String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
          private static String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
      
          public static SubmitTranscodeJobsResponse submitTranscodeJobs(DefaultAcsClient client) throws Exception{
              SubmitTranscodeJobsRequest request = new SubmitTranscodeJobsRequest();
              request.setTemplateGroupId("");
              request.setVideoId("");
              JSONObject encryptConfig = new JSONObject();
              encryptConfig.put("CipherText","");
              encryptConfig.put("DecryptKeyUri","");
              encryptConfig.put("KeyServiceType","KMS");
              request.setEncryptConfig(encryptConfig.toJSONString());
              return client.getAcsResponse(request);
          }
      
          public static void main(String[] args) throws ClientException {
              String regionId = "cn-shanghai";  // Specify the region where ApsaraVideo VOD is activated.
              DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
              DefaultAcsClient client = new DefaultAcsClient(profile);
      
              SubmitTranscodeJobsResponse response;
              try {
                  response = submitTranscodeJobs(client);
                  System.out.println("RequestId is:"+response.getRequestId());
                  System.out.println("TranscodeTaskId is:"+response.getTranscodeTaskId());
                  System.out.println("TranscodeJobs is:"+ JSON.toJSON(response.getTranscodeJobs()));
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }       
    2. If you have configured event notifications in ApsaraVideo VOD, video transcoding completes when you receive either a StreamTranscodeComplete or TranscodeComplete callback.

  5. View the HLS encryption result.

    After the transcoding is complete, you can determine whether HLS encryption is successful by using the following methods:

    • Method 1: Log on to the ApsaraVideo VOD console. In the left-side navigation pane, choose Media Files > Audio/Video. On the Video and Audio page, find the video that you uploaded and click Manage in the Actions column. On the Video URL tab, if video outputs in formats other than the MP4 format exist, and HLS Encryption is tagged on M3U8 files, HLS encryption is successful.视频安全-HLS标准加密5

    • Method 2: Copy the URL of an M3U8 file on which HLS Encryption is tagged, run the curl -v "URL of the M3U8 file" command, and then check the result. If the decryption URL that you specify when you start HLS encryption is the same as the value of DecryptKeyUri, HLS encryption is successful.

    • Method 3: Call the GetTranscodeTask operation and pass the value of the JobId parameter that is returned in Step 4. If the value of TranscodeTemplateId in the response matches the ID of the transcoding template group created in Step 3 and TranscodeJobStatus shows "Transcoding succeeded," HLS encryption is successful.

(Recommended) M3U8 encryption and rewrite

After you enable the M3U8 encryption and rewrite feature, the system will automatically add encryption parameters (such as the encryption algorithm, key URI, and authentication parameters) after the #EXT-X-KEY tag in the M3U8 playlist file. When the client processes the rewritten M3U8 playlist file, it uses the key URI (which includes authentication parameters) to request the decryption key. The client then decrypts the transport stream (TS) files by using this key and the specified algorithm, ensuring encrypted access to HLS streams.

Step 1: Enable parameter pass-through for HLS encryption

Log on to the ApsaraVideo VOD console and turn on Parameter Pass-through for HLS Encryption.

After you enable Parameter Pass-through for HLS Encryption, the M3U8 playlist file can be modified. Specifically, it involves modifying the URI in the #EXT-X-KEY tag by appending the parameters carried in the client request at the end. By default, MtsHlsUriToken is rewritten.

Prerequisites

Cross-origin resource sharing (CORS) is configured.

Important

Alibaba Cloud Gov Cloud does not support parameter pass-through for HLS encryption.

Procedure

  1. Log on to the ApsaraVideo VOD console.

  2. In the left-side navigation pane, find Configuration Management.

  3. Choose CDN Configuration > Domain Names. The Domain Names page is displayed.

  4. Find the domain name that you want to configure and click Configure in the Actions column.

  5. In the left-side navigation pane of the domain name, click Video Related.

  6. In the Encrypted Playback section, turn on Parameter Pass-through for HLS Encryption.p181836

Note
  • Once you enable this feature, the system will automatically handle authentication by rewriting the Token parameter when you pass HLS encryption parameters. The rewritten parameter is MtsHlsUriToken, and its value is test. During CDN decryption and playback, MtsHlsUriToken=test will be appended to the end of the URI in the #EXT-X-KEY tag of the M3U8 playlist file.

Step 2: Send a request that includes the MtsHlsUriToken parameter

Send a request to the point of presence (POP) to access the M3U8 playlist file and include MtsHlsUriToken in the request.

To obtain MtsHlsUriToken, you must set up a token service.

The following sample code shows how to obtain MtsHlsUriToken. The following table describes the parameters in the sample code. You can modify them based on your business needs.

Sample code in Java

Parameter

Description

ENCRYPT_KEY

The encryption key. You can specify a custom string that is 16, 24, or 32 characters in length.

INIT_VECTOR

The encryption offset. You can specify a custom string that is 16 characters in length. The value cannot contain special characters.

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;

public class PlayToken {
    // The following parameters are not required if you do not use the AES algorithm to generate a token.
    private static String ENCRYPT_KEY = ""; // A custom encryption key. The string must be 16, 24, or 32 characters in length.
    private static String INIT_VECTOR = ""; // A custom encryption offset. The string must be 16 characters in length and cannot contain special characters.

    public static void main(String[] args) throws Exception {

        String serviceId = "12";
        PlayToken playToken = new PlayToken();
        String aesToken = playToken.generateToken(serviceId);
        //System.out.println("aesToken " + aesToken);
        //System.out.println(playToken.validateToken(aesToken));   // Verify the token.
    }
    /**
     * Generate a token based on the configured parameters.
     * Notes:
     * 1. The parameters include the user ID and the type of the playback device.
     * 2. A token is generated when the token operation is called.
     * @param args
     * @return
     */
    public String generateToken(String... args) throws Exception {
        if (null == args || args.length <= 0) {
            return null;
        }
        String base = StringUtils.join(Arrays.asList(args), "_");
        // Set the validity period of a token to 30 seconds. You can change the value based on your business requirements.
        long expire = System.currentTimeMillis() + 30000L;
        base += "_" + expire;   // A custom string that is 16 characters in length. In this example, 2 more characters are required because the timestamp contains 13 characters and the underscore (_) is 1 character in length. You can change the value of the base parameter. The value must be 16, 24, or 32 characters in length.
        // Generate a token.
        String token = encrypt(base, ENCRYPT_KEY);  // arg1 is the custom string to be encrypted. arg2 is the encryption key.
        // Save the token. The validity of the token is checked during decryption, such as the validity period and the number of times that the token is used.
        saveToken(token);
        return token;
    }

    /**
     * Check whether the token is valid.
     * Notes:
     * 1. Before the decryption operation returns the playback key, the decryption service checks whether the token is legitimate and valid.
     * 2. We recommend that you check the validity period of the token and the number of times the token is used.
     * @param token
     * @return
     * @throws Exception
     */
    public boolean validateToken(String token) throws Exception {
        if (null == token || "".equals(token)) {
            return false;
        }
        String base = decrypt(token,ENCRYPT_KEY); // arg1 is the string to be decrypted. arg2 is the decryption key.
        // Check the validity period of the token.
        Long expireTime = Long.valueOf(base.substring(base.lastIndexOf("_") + 1));
        System.out.println("Check the validity period:" + expireTime);
        if (System.currentTimeMillis() > expireTime) {
            return false;
        }
        // Obtain the token information from the database and check whether the token is valid. You can customize the logic.
        TokenInfo dbToken = getToken(token);
        // Check whether the token is used.
        if (dbToken == null || dbToken.useCount > 0) {
            return false;
        }
        // Obtain the business attributes for verification.
        String businessInfo = base.substring(0, base.lastIndexOf("_"));
        String[] items = businessInfo.split("_");
        // Check the validity of the business attributes. You can customize the logic.
        return validateInfo(items);
    }
    /**
     * Save the token to the database.
     * You can customize the logic.
     *
     * @param token
     */
    public void saveToken(String token) {
        // TODO. Save the token.
    }
    /**
     * Query the token.
     * You can customize the logic.
     *
     * @param token
     */
    public TokenInfo getToken(String token) {
        // TODO. Obtain the token from the database and check whether the token is valid.
        return null;
    }
    /**
     * Check the validity of the business attributes. You can customize the logic.
     *
     * @param infos
     * @return
     */
    public boolean validateInfo(String... infos) {
        // TODO. Check the validity of the information, such as the UID.
        return true;
    }
    /**
     * Generate a token by using the AES algorithm.
     *
     * @param encryptStr  The string to be encrypted.
     * @param encryptKey  The encryption key.
     * @return
     * @throws Exception
     */
    public String encrypt(String encryptStr, String encryptKey) throws Exception {
        IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(encryptKey.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, e);
        byte[] encrypted = cipher.doFinal(encryptStr.getBytes());
        return Base64.encodeBase64String(encrypted);
    }
    /**
     * Decrypt the token by using the AES algorithm.
     *
     * @param encryptStr  The string to be decrypted.
     * @param decryptKey  The decryption key.
     * @return
     * @throws Exception
     */
    public String decrypt(String encryptStr, String decryptKey) throws Exception {

        IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
        SecretKeySpec skeySpec = new SecretKeySpec(decryptKey.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, e);

        byte[] encryptByte = Base64.decodeBase64(encryptStr);
        byte[] decryptByte = cipher.doFinal(encryptByte);
        return new String(decryptByte);
    }
    /**
     * Obtain the token information. The sample code is for reference only. You can obtain additional token information based on your business scenario.
     */
    class TokenInfo {
        // Obtain the number of times that the token is used. Modifications must be synchronized in a distributed environment.
        int useCount;
        // The content of the token.
        String token;
    }}
                        

Step 3: Decrypt the playback file

After receiving the client request, the POP will decrypt the playback file upon successful authentication.

If the value of MtsHlsUriToken generated in Step 2 is test, Alibaba Cloud CDN will append MtsHlsUriToken=test to the end of the URI in the #EXT-X-KEY tag of the M3U8 playlist file during decryption and playback.

You need to implement the authentication validation logic on your own. For reference, you can review the sample code provided for setting up a decryption service with M3U8 encryption and rewrite enabled in the Play videos section.

Play videos

(Recommended) M3U8 encryption and rewrite enabled

  1. Set up a decryption service.

    Set up a local HTTP service to decrypt your video.

    Call the DecryptKMSDataKey operation to decrypt the DK. The PlainText value in the response contains the DK. This DK is the Base64-decoded version of the PlainText parameter returned in the response to the GenerateKMSDataKey operation.

    If you want to verify the decryption URL, enable M3U8 encryption and rewrite. By default, MtsHlsUriToken is rewritten. This way, your data is protected during HLS data access. The code used to set up a decryption service varies based on whether the M3U8 encryption and rewrite feature is enabled or not. The following section describes the sample code:

    Sample code in Java

    The following table describes the parameters in the sample code. You can modify them based on your business needs.

    Parameter

    Description

    region

    The region ID. KMS and ApsaraVideo VOD must be activated in the same region. For example, if you activate KMS and ApsaraVideo VOD in China (Shanghai), specify cn-shanghai for this parameter. For more information about the IDs of other regions, see Region IDs of ApsaraVideo VOD.

    AccessKey

    The AccessKey ID and AccessKey secret of your Alibaba Cloud account or RAM user. For more information about how to obtain an AccessKey pair, see Obtain an AccessKey pair.

    httpserver

    The port number that you want to use to activate the service.

    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyRequest;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyResponse;
    import com.aliyuncs.profile.DefaultProfile;
    import com.sun.net.httpserver.Headers;
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.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;
    public class HlsDecryptServer {
        private static DefaultAcsClient client;
        static {
            // The region where KMS is used. The region must be the same as the region where the video resides.
            String region = "";
            // The AccessKey pair that is used to authorize access to KMS.
            // The AccessKey pair of an Alibaba Cloud account has permissions to call all API operations. We recommend that you use the AccessKey pair of a RAM user to call API operations or perform routine O&M. 
            // We recommend that you do not hardcode your AccessKey pair (AccessKey ID and AccessKey secret) in your project code. Otherwise, the AccessKey pair may be leaked and the security of all resources within your account may be compromised. 
            // In this example, ApsaraVideo VOD reads the AccessKey pair from environment variables to implement identity verification for API access. Before you run the sample code, configure the following environment variables: ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET. 
            String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
            String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
            client = new DefaultAcsClient(DefaultProfile.getProfile(region, accessKeyId, accessKeySecret));
        }
        /**
         * Notes:
         * 1. Receive a decryption request and obtain the EDK and token.
         * 2. Call the DecryptKMSDataKey operation of KMS to obtain the DK.
         * 3. Decode the DK by using the Base64 algorithm and return the DK.
         */
        public class HlsDecryptHandler 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)) {
                    // Check whether the token is valid.
                    String token = getMtsHlsUriToken(httpExchange);
                    boolean validRe = validateToken(token);
                    if (!validRe) {
                        return;
                    }
                    // Obtain the EDK from the video URL.
                    String ciphertext = getCiphertext(httpExchange);
                    if (null == ciphertext)
                        return;
                    // Decode the DK obtained from KMS by using the Base64 algorithm and return the DK.
                    byte[] key = decrypt(ciphertext);
                    // Configure the header.
                    setHeader(httpExchange, key);
                    // Return the DK decoded by using the Base64 algorithm.
                    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);
            }
            /**
             * Call the decryption operation of KMS to decrypt the DK and decode the DK by using the Base64 algorithm.
             * @param ciphertext
             * @return
             */
            private byte[] decrypt(String ciphertext) {
                DecryptKMSDataKeyRequest request = new DecryptKMSDataKeyRequest();
                request.setCipherText(ciphertext);
                request.setProtocol(ProtocolType.HTTPS);
                try {
                    DecryptKMSDataKeyResponse response = client.getAcsResponse(request);
                    String plaintext = response.getPlaintext();
                    System.out.println("PlainText: " + plaintext);
                    // Note: You must decode the DK by using the Base64 algorithm.
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            /**
             * Obtain the EDK from the video URL.
             * @param httpExchange
             * @return
             */
            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 Param");
                    return null;
                }
            }
            
              /**
             * Check the token validity, which is essential for M3U8 encryption and rewrite.
             * @param token
             * @return
             */
            private boolean validateToken(String token) {
                if (null == token || "".equals(token)) {
                    return false;
                }
                // TODO. You can customize the logic to check whether the token is valid.
                return true;
            }
            /**
             * Obtain the Token parameter, which is essential for M3U8 encryption and rewrite.
             *
             * @param httpExchange
             * @return
             */
            private String getMtsHlsUriToken(HttpExchange httpExchange) {
                URI uri = httpExchange.getRequestURI();
                String queryString = uri.getQuery();
                String pattern = "MtsHlsUriToken=(\\w*)";
                Pattern r = Pattern.compile(pattern);
                Matcher m = r.matcher(queryString);
                if (m.find())
                    return m.group(1);
                else {
                    System.out.println("Not Found MtsHlsUriToken Param");
                    return null;
                }
            }
        }
        /**
         * Start the service.
         *
         * @throws IOException
         */
        private void serviceBootStrap() throws IOException {
            HttpServerProvider provider = HttpServerProvider.provider();
            // You can specify a custom port for listening. A web server can handle a maximum of 30 requests simultaneously on the same port.
            HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8099), 30);
            httpserver.createContext("/", new HlsDecryptHandler());
            httpserver.start();
            System.out.println("hls decrypt server started");
        }
        public static void main(String[] args) throws IOException {
            HlsDecryptServer server = new HlsDecryptServer();
            server.serviceBootStrap();
        }}
  2. Obtain the playback URL and credential of your encrypted video.

    Call the GetVideoPlayAuth operation to obtain the playback credential and call the GetPlayInfo operation to obtain the playback URL.

  3. Play the encrypted video.

    HLS encryption supports all HLS-compatible players. You can use a self-developed player or ApsaraVideo Player to play encrypted videos.

    If you use ApsaraVideo Player to play encrypted videos, you must obtain the token and authentication information. For more information, see How to play encrypted videos. If you use a third-party player, implement the playback logic on your own.

    The following procedure describes how ApsaraVideo Player tests the playback:

    (Recommended) M3U8 encryption and rewrite enabled

    Process

    • The player parses the EXT-X-KEY tag in the M3U8 playlist file to retrieve the decryption key URI, which corresponds to the DecryptKeyUri value in EncryptConfig.

    • To restrict unauthorized access, the player must include authentication information (passed through the MtsHlsUriToken parameter) when requesting the decryption operation.

    • The player automatically calls the DecryptKMSDataKey operation to obtain the DK, decrypts the encrypted TS files, and then proceeds with normal playback.

    Example

    • The video playback URL is https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8. The request must contain the MtsHlsUriToken parameter.

    • The final request URL is https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8?MtsHlsUriToken=<Token>.

    • The decryption URL is https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****.

    • The final request URL for decryption is https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****&MtsHlsUriToken=<The issued token>.

M3U8 encryption and rewrite disabled

  1. Set up a decryption service.

    Set up a local HTTP service to decrypt your video.

    Call the DecryptKMSDataKey operation to decrypt the DK. The PlainText value in the response contains the DK. This DK is the Base64-decoded version of the PlainText parameter returned in the response to the GenerateKMSDataKey operation.

    Sample code:

    Sample code in Java

    The following table describes the parameters in the sample code. You can modify them based on your business needs.

    Parameter

    Description

    region

    The region ID. KMS and ApsaraVideo VOD must be activated in the same region. For example, if you activate KMS and ApsaraVideo VOD in China (Shanghai), specify cn-shanghai for this parameter. For more information about the IDs of other regions, see Region IDs of ApsaraVideo VOD.

    AccessKey

    The AccessKey ID and AccessKey secret of your Alibaba Cloud account or RAM user. For more information about how to obtain the AccessKey pair, see Obtain an AccessKey pair.

    httpserver

    The port number that you want to use to activate the service.

    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyRequest;
    import com.aliyuncs.vod.model.v20170321.DecryptKMSDataKeyResponse;
    import com.sun.net.httpserver.Headers;
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.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;
    
    public class HlsDecryptServerNoToken {
    
        private static DefaultAcsClient client;
        static {
            // The region where KMS is used. The region must be the same as the region where the video resides.
            String region = "cn-beijing";
            // The AccessKey pair that is used to authorize access to KMS.
            // The AccessKey pair of an Alibaba Cloud account has permissions to call all API operations. We recommend that you use the AccessKey pair of a RAM user to call API operations or perform routine O&M. 
            // We recommend that you do not hardcode your AccessKey pair (AccessKey ID and AccessKey secret) in your project code. Otherwise, the AccessKey pair may be leaked and the security of all resources within your account may be compromised. 
            // In this example, ApsaraVideo VOD reads the AccessKey pair from environment variables to implement identity verification for API access. Before you run the sample code, configure the following environment variables: ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET. 
            String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
            String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
            client = new DefaultAcsClient(DefaultProfile.getProfile(region, accessKeyId, accessKeySecret));
        }
        /**
         * Notes:
         * 1. Receive a decryption request and obtain the EDK and token.
         * 2. Call the DecryptKMSDataKey operation of KMS to obtain the DK.
         * 3. Decode the DK by using the Base64 algorithm.
         */
        public class HlsDecryptHandler 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)) {
    
                    // Obtain the EDK from the video URL.
                    String ciphertext = getCiphertext(httpExchange);
                    System.out.println(ciphertext);
                    if (null == ciphertext)
                        return;
                    // Decode the DK obtained from KMS by using the Base64 algorithm and return the DK.
                    byte[] key = decrypt(ciphertext);
                    // Configure the header.
                    setHeader(httpExchange, key);
                    // Return the DK that is decoded by using the Base64 algorithm.
                    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);
            }
            /**
             * Call the decryption operation of KMS to decrypt the DK and decode the DK by using the Base64 algorithm.
             * @param ciphertext
             * @return
             */
            private byte[] decrypt(String ciphertext) {
    
                DecryptKMSDataKeyRequest request = new DecryptKMSDataKeyRequest();
                request.setCipherText(ciphertext);
                request.setProtocol(ProtocolType.HTTPS);
                try {
                    DecryptKMSDataKeyResponse response = client.getAcsResponse(request);
                    String plaintext = response.getPlaintext();
                    System.out.println("PlainText: " + plaintext);
                    // Note: You must decode the DK by using the Base64 algorithm.
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
    
            /**
             * Obtain the EDK from the video URL.
             * @param httpExchange
             * @return
             */
            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 Param");
                    return null;
                }
            }
        }
    
        /**
         * Start the service.
         *
         * @throws IOException
         */
        private void serviceBootStrap() throws IOException {
            HttpServerProvider provider = HttpServerProvider.provider();
            // You can specify a custom port for listening. A web server can handle a maximum of 30 requests simultaneously on the same port.
            HttpServer httpserver = provider.createHttpServer(new InetSocketAddress(8099), 30);
            httpserver.createContext("/", new HlsDecryptHandler());
            httpserver.start();
            System.out.println("hls decrypt server started");
        }
        public static void main(String[] args) throws IOException {
            HlsDecryptServerNoToken server = new HlsDecryptServerNoToken();
            server.serviceBootStrap();
        }}
    
  2. Obtain the playback URL and credential of your encrypted video.

    Call the GetVideoPlayAuth operation to obtain the playback credential and call the GetPlayInfo operation to obtain the playback URL.

  3. Play the encrypted video.

    HLS encryption supports all HLS-compatible players. You can use a self-developed player or ApsaraVideo Player to play encrypted videos.

    If you use ApsaraVideo Player to play encrypted videos, you must obtain the token and authentication information. For more information, see How to play encrypted videos. If you use a third-party player, implement the playback logic on your own.

    The following procedure describes how ApsaraVideo Player tests the playback:

    M3U8 encryption and rewrite disabled

    Process

    • The player parses the EXT-X-KEY tag in the M3U8 file to retrieve the decryption key URI, which corresponds to the DecryptKeyUri value in EncryptConfig.

    • The player automatically calls the DecryptKMSDataKey operation to obtain the DK, decrypts the encrypted TS files, and then proceeds with normal playback.

    Example

    • The video playback URL is https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8.

    • The final request URL is https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8.

    • The decryption URL is https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****.

    • The final request URL for decryption is https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****.

References