All Products
Search
Document Center

ApsaraVideo VOD:HLS encryption

Last Updated:Apr 30, 2026

HLS encryption uses the AES-128 algorithm, is compatible with all HLS players, and requires integration with key management and token services. It is widely used in scenarios that require a high level of security, such as online education and exclusive video streaming. This topic describes how to encrypt your videos by using HLS encryption and decrypt them for playback.

How it works

ApsaraVideo VOD uses envelope encryption. Your application generates a data key (DK) and an enveloped data key (EDK) using Alibaba Cloud Key Management Service (KMS). After the DK is used to encrypt a video, the encrypted video and the EDK are stored. During playback, a decryption service obtains the DK to decrypt the video.

If you need to secure decryption URLs, you can enable M3U8 encryption and rewrite (the default rewrite parameter is MtsHlsUriToken) to add another layer of encryption to protect HLS data access. For more information about how to enable this feature and its technical principles, see Configure M3U8 encryption and rewrite.

Prerequisites

  • Alibaba Cloud video encryption, specifically HLS encryption, is a free service. However, it requires video transcoding to perform the encryption, and transcoding operations incur fees. For more information about billing, see Media transcoding billing.

  • You have activated ApsaraVideo VOD. For more information, see Activate ApsaraVideo VOD.

  • You have authorized ApsaraVideo VOD to access your Key Management Service (KMS) resources. You can grant the required permissions on the Cloud Resource Access Authorization page.

  • You have configured an accelerated domain name in ApsaraVideo VOD. For more information, see Add an accelerated domain name.

  • You have installed the ApsaraVideo VOD server-side SDK. This topic uses the SDK for Java as an example. For more information, see Server-side SDK.

Key concepts

Concept

Description

Resource Access Management (RAM)

A service provided by Alibaba Cloud that allows you to manage user identities and control access to resources. For more information, see What is RAM?.

Key Management Service (KMS)

A one-stop platform for key management and data encryption. It provides simple, reliable, secure, and compliant capabilities for encryption, protection, and credential management. For more information, see What is Key Management Service?.

data key (DK)

A plaintext key used to encrypt data. For more information, see Basic concepts.

enveloped data key (EDK)

A ciphertext data key that is protected using envelope encryption. For more information, see Basic concepts.

Encryption and decryption workflow

Upload and encryption workflow

视频安全-HLS标准加密3

Decryption and playback workflow

With rewrite (recommended)

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

Without rewrite

视频安全-HLS标准加密2

Encrypt a video

  1. Upload a video and receive callbacks.

    To prevent videos that support HLS encryption from being automatically transcoded, select the built-in No Transcoding template group when you upload videos to ApsaraVideo VOD. This prevents the upload from triggering a transcoding job.

    1. Upload the video by using the ApsaraVideo VOD console or by calling an API operation for media upload.

    2. Configure event notifications for ApsaraVideo VOD. When you receive a callback for a Video Upload Complete event, it indicates that the video is uploaded to ApsaraVideo VOD. For information about how to configure event notifications, see Event notifications.

  2. Set up an encryption service.

    1. Create a Service Key.

      A Service Key is the primary encryption key in Key Management Service (KMS) required to generate keys for HLS encryption. If you do not create a Service Key, the call to the GenerateKMSDataKey operation will fail.

      1. In the upper-left corner of the page, click the region ID to switch to the region where you want to create the Service Key.

        Note

        The Service Key must be in the same region as your video's origin server. For example, if your video is stored in China (Shanghai), you must create the Service Key in the China (Shanghai) region.

        标准加密-服务地域

      2. Log on to the ApsaraVideo VOD console, and select Configuration Management > Media Processing > HLS Standard Encryption.

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

        After the key is created, a message appears indicating that the Service Key is created. You can then view your Service Key in the Key Information section.

        Note

        If a success message is displayed but you cannot see the Service Key, a service-linked role might be missing. You can click reauthorize to restore the role and then refresh the page to view the Service Key.

    2. Call an API to generate a data key.

      Call the GenerateKMSDataKey operation to generate a data key (DK) and an enveloped data key (EDK). You do not need to pass any parameters. On success, the returned CiphertextBlob is the EDK in AES-128 format. Cache this value for the HLS encryption transcoding job. The returned Plaintext is the DK.

  3. Create a transcoding template group for HLS encryption.

    The HLS encryption process requires two transcoding template groups: the built-in No Transcoding template group and a custom HLS encryption template group that you must create. Follow these steps to create the HLS encryption template group:

    1. Log on to the ApsaraVideo VOD console, and select Configuration Management > Media Processing > Transcoding Template Groups.

    2. On the Transcoding Template Groups page, create a template group for HLS encryption.

      Set Encapsulation Format to hls. In the Advanced Parameters section, you must enable Video Encryption and select Alibaba Cloud Encryption as the encryption method. Configure other parameters based on your business requirements. For detailed parameter descriptions, see Transcoding templates.

    3. After the template is created, you can view the ID of the transcoding template group on the transcoding template group list page. Save this ID to initiate the HLS encryption transcoding job.视频安全-HLS加密-控制台1

  4. Initiate an HLS encryption transcoding job.

    1. Call the SubmitTranscodeJobs operation to initiate the HLS encryption transcoding job.

      Java sample code

      The following table describes the parameters in the sample Java code that you need to change based on your requirements.

      Parameter

      Value

      request.setTemplateGroupId("")

      The ID of the transcoding template group for HLS encryption that you created in Step 3.

      request.setVideoId("")

      The ID of the video to be encrypted that you uploaded in Step 1.

      encryptConfig.put("CipherText","")

      Pass the CiphertextBlob value returned in Step 2.

      encryptConfig.put("DecryptKeyUri","")

      Pass in the key URI address, which is a concatenation of the decryption service address and the CiphertextBlob value. For example, for a service on local port 8099, the key URI address is as follows:

      http://172.16.0.1:8099?CipherText=CiphertextBlobValue

      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 {
      
          // An AccessKey pair of an Alibaba Cloud account has full permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M.
          // To protect your resources, do not hardcode the AccessKey ID and AccessKey secret in your project code. Leaked AccessKey pairs may compromise the security of all your resources.
          // This example demonstrates how to use environment variables to obtain the AccessKey pair for identity verification. Before you run the code, configure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.
          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";  // 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 for ApsaraVideo VOD, receiving a callback message for a Single Definition Transcoding Complete or All Definitions Transcoding Complete event indicates that the video transcoding is complete.

  5. Verify the HLS encryption result.

    After transcoding is complete, you can use one of the following three methods to verify that the HLS encryption was successful.

    • Method 1: Log on to the ApsaraVideo VOD console and select Media Files > Audio/Video > Manage > Video URL. On the Video URL page, if the video has outputs in multiple formats, such as an original file in MP4 format, you only need to check whether the M3U8 video stream is labeled with HLS Standard Encryption. If the label is present, it indicates that HLS encryption is successful.Video security-HLS encryption 5

    • Method 2: Copy the URL of the M3U8 file that is labeled HLS Standard Encryption, run the curl -v "M3U8 file URL" command, and check if the returned M3U8 content contains the key information URI="<The decryption URI that you pass when you initiate standard encryption, which is the value of the DecryptKeyUri parameter>". If this information is present, it indicates that Standard Encryption is used and the encryption was successful.

    • Method 3: Call the GetTranscodeTask operation, passing the JobId value returned in Step 4. If the returned TranscodeTemplateId matches the ID of the transcoding template group created in Step 3 and the TranscodeJobStatus is TranscodeSuccess, the HLS encryption was successful.

M3U8 encryption and rewrite (recommended)

When you enable the M3U8 encryption and rewrite feature, the system appends encryption parameters, such as the encryption algorithm, key URI, and authentication parameters, after the #EXT-X-KEY tag in the HLS media playlist (M3U8 file). When a client parses the rewritten M3U8 file, it uses the key URI with authentication parameters to request the key. The client then uses the key and the specified algorithm to decrypt the TS segments, ensuring secure, encrypted access to the HLS stream.

Step 1: Enable Parameter Pass-through for HLS Encryption

In the ApsaraVideo VOD console, enable Parameter Pass-through for HLS Encryption.

After you enable Parameter Pass-through for HLS Encryption, the system rewrites the HLS M3U8 file by modifying the URI in the #EXT-X-KEY tag. It appends parameters from the client request to the URI. The default parameter name is MtsHlsUriToken.

Prerequisites

Cross-origin resource sharing (CORS) is configured. For more information, see Configure cross-origin resource sharing.

Important

Alibaba Cloud Gov Cloud does not support this feature.

Procedure

  1. Log on to the ApsaraVideo VOD console.

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

  3. Click CDN Configuration > Domain Names to go to the Domain Names page.

  4. Find the desired domain name and click Configure in the Actions column.

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

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

Note
  • When this feature is enabled, it authenticates requests for Parameter Pass-through for HLS Encryption by rewriting the token authentication parameter. The name of the rewritten parameter is MtsHlsUriToken, and its value is test. When the CDN decrypts the content for playback, MtsHlsUriToken=test is appended to the end of the URI in the #EXT-X-KEY tag of the M3U8 file.

Step 2: Request with MtsHlsUriToken

The client sends a request to the CDN node to access the M3U8 file, including the MtsHlsUriToken parameter.

To obtain the MtsHlsUriToken, you must build a token service that issues user tokens.

The token generated by the following code is the MtsHlsUriToken. The following table describes the parameters in the code that you need to change based on your requirements.

Java sample code

Parameter

Value

ENCRYPT_KEY

The encryption key, which is a custom string of 16, 24, or 32 bytes in length.

INIT_VECTOR

The initialization vector, which is a custom string of 16 bytes in length and 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 not using AES generation.
    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 initialization vector. 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));   // Decryption validation part.
    }
    /**
     * Generates a token based on the passed parameters.
     * Notes:
     *  1. Parameters can include your business-side user ID, playback device type, etc.
     *  2. A token is generated when the token service endpoint 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 token to expire after 30 seconds. You can adjust the expiration time.
        long expire = System.currentTimeMillis() + 30000L;
        base += "_" + expire;   // Custom string. The length of base must be 16 bytes. In this example, the timestamp is 13 bytes and the underscore is 1 byte, so 2 more bytes are needed. You can change this as needed, but ensure the final base is 16, 24, or 32 bytes.
        // Generate the token.
        String token = encrypt(base, ENCRYPT_KEY);  // arg1 is the custom string to encrypt, arg2 is the encryption key.
        // Save the token to validate it during decryption (e.g., check expiration time, usage count).
        saveToken(token);
        return token;
    }

    /**
     * Validates the token.
     * Notes:
     *  1. Before returning the playback key, the decryption service must validate the token's legitimacy and validity.
     *  2. We strongly recommend checking both the token's expiration time and its valid usage count.
     * @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 decrypt, arg2 is the decryption key.
        // First, validate the token's expiration time.
        Long expireTime = Long.valueOf(base.substring(base.lastIndexOf("_") + 1));
        System.out.println("Time validation: " + expireTime);
        if (System.currentTimeMillis() > expireTime) {
            return false;
        }
        // Get token info from DB to check validity. Implement this based on your business logic.
        TokenInfo dbToken = getToken(token);
        // Check if the token has already been used.
        if (dbToken == null || dbToken.useCount > 0) {
            return false;
        }
        // Get business attribute information for validation.
        String businessInfo = base.substring(0, base.lastIndexOf("_"));
        String[] items = businessInfo.split("_");
        // Validate the legitimacy of the business information. Implement this based on your business logic.
        return validateInfo(items);
    }
    /**
     * Save the token to the database.
     * Implement this based on your business logic.
     *
     * @param token
     */
    public void saveToken(String token) {
        //TODO: Store the token.
    }
    /**
     * Query the token.
     * Implement this based on your business logic.
     *
     * @param token
     */
    public TokenInfo getToken(String token) {
        //TODO: Get token info from the DB for validity and legitimacy checks.
        return null;
    }
    /**
     * Validate the business information.
     * Implement this based on your business logic.
     *
     * @param infos
     * @return
     */
    public boolean validateInfo(String... infos) {
        //TODO: Validate the information, such as whether the UID is valid.
        return true;
    }
    /**
     * Encrypt with AES to generate the token.
     *
     * @param encryptStr  The string to encrypt.
     * @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 with AES.
     *
     * @param encryptStr  The string to decrypt.
     * @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);
    }
    /**
     * Token information. You can include more info based on your business needs. This is just an example.
     */
    class TokenInfo {
        // The number of times the token can be used. In a distributed environment, you need to handle synchronous modifications.
        int useCount;
        // The token content.
        String token;
    }}
                        
Note

The preceding code is an open-source example. It does not involve any SDKs or service-related code. You must configure and adjust it based on your business requirements.

Step 3: Decrypt and play the file

After the CDN node receives the client request, it authenticates the request and, if successful, decrypts the file for playback.

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

You must implement the authentication logic yourself. For reference, see the sample code for the decryption service in the M3U8 encryption and rewrite method in the Play the video section.

Play the video

With rewrite (recommended)

  1. Set up a decryption service.

    Set up a local HTTP service to decrypt the video.

    Calling the Decrypt KMS Data Key Ciphertext operation returns the data key (DK) as PlainText. This key is the result of Base64-decoding the PlainText that is returned by the Create KMS Data Key operation.

    If you need to perform security verification for decryption URLs, you can enable M3U8 encryption and rewrite (the default parameter name is MtsHlsUriToken) to add another layer of encryption to protect the HLS data access process. The code implementation for the decryption service differs depending on whether you enable M3U8 encryption and rewrite. The details are as follows:

    Java sample code

    The following table describes the parameters in the sample Java code that you need to change based on your requirements.

    Parameter

    Value

    region

    The region ID. The region of the Key Management Service (KMS) must be the same as the ApsaraVideo VOD region. For example, for China (Shanghai), enter cn-shanghai. For other region IDs, see ApsaraVideo VOD region IDs.

    AccessKey

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

    httpserver

    The port number to start the service on, based on your requirements.

    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 of KMS, which must be the same as the video's region.
            String region = "";
            // AccessKey information for accessing KMS.
            // An AccessKey pair of an Alibaba Cloud account has full permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M.
            // To protect your resources, do not hardcode the AccessKey ID and AccessKey secret in your project code. Leaked AccessKey pairs may compromise the security of all your resources.
            // This example demonstrates how to use environment variables to obtain the AccessKey pair for identity verification. Before you run the code, configure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.
            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 to get the ciphertext key and user token.
         * 2. Call the KMS decrypt API to get the plaintext key.
         * 3. Return the Base64-decoded plaintext key.
         */
        public class HlsDecryptHandler implements HttpHandler {
            /**
             * Handle the decryption request.
             * @param httpExchange
             * @throws IOException
             */
            public void handle(HttpExchange httpExchange) throws IOException {
                String requestMethod = httpExchange.getRequestMethod();
                if ("GET".equalsIgnoreCase(requestMethod)) {
                    // Validate the token.
                    String token = getMtsHlsUriToken(httpExchange);
                    boolean validRe = validateToken(token);
                    if (!validRe) {
                        return;
                    }
                    // Get the ciphertext key from the URL.
                    String ciphertext = getCiphertext(httpExchange);
                    if (null == ciphertext)
                        return;
                    // Decrypt from KMS and Base64 decode.
                    byte[] key = decrypt(ciphertext);
                    // Set the header.
                    setHeader(httpExchange, key);
                    // Return the Base64-decoded key.
                    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 KMS decrypt API and Base64 decode the plaintext.
             * @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: The plaintext needs to be Base64-decoded.
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            /**
             * Get the ciphertext key parameter from the 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;
                }
            }
            
              /**
             * Validate the token. This is required for M3U8 encryption and rewrite.
             * @param token
             * @return
             */
            private boolean validateToken(String token) {
                if (null == token || "".equals(token)) {
                    return false;
                }
                //TODO: Implement your own token validation logic.
                return true;
            }
            /**
             * Get the Token parameter. This is required 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();
            // The listening port can be customized. It can handle up to 30 requests simultaneously.
            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.

    Call the GetVideoPlayAuth operation to get the playback credential or call the GetPlayInfo operation to get the playback URL.

  3. Play the encrypted video.

    HLS encryption is compatible with all HLS players. You can use your own player or ApsaraVideo Player to play the encrypted video.

    If you use ApsaraVideo Player, you must obtain a token and authentication information required by the player before starting playback. For more information, see Play encrypted videos. If you use a player other than ApsaraVideo Player, you must implement your own playback logic.

    The following section describes the internal workflow for playback with ApsaraVideo Player:

    With rewrite (recommended)

    Workflow

    • The player parses the EXT-X-KEY tag in the M3U8 file to obtain the decryption key URI. This URI corresponds to the value of the DecryptKeyUri parameter in EncryptConfig.

    • To prevent unauthorized access, the player must include authentication information (passed in the MtsHlsUriToken parameter) when it requests the decryption endpoint.

    • The player requests the decryption endpoint to get the key, decrypts the TS files, and plays the video.

    Example

    • If the video playback URL is https://demo.aliyundoc.com/encrypt-stream****-hd.m3u8, you must include the MtsHlsUriToken parameter in the request.

    • 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 decryption request URL is: https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****&MtsHlsUriToken=<issued token>

Without rewrite

  1. Set up a decryption service.

    Set up a local HTTP service to decrypt the video.

    Call the Decrypt operation to decrypt the ciphertext of a KMS data key. The returned data key (DK), which is the PlainText value, is the result of base64-decoding the PlainText value that is returned by the CreateDataKey operation.

    The following is a code sample:

    Java sample code

    The following table describes the parameters in the sample Java code that you need to change based on your requirements.

    Parameter

    Value

    region

    The region ID. The KMS service and ApsaraVideo VOD must be in the same region. For example, the region ID for China (Shanghai) is cn-shanghai. For other region IDs, see VOD Region IDs.

    AccessKey

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

    httpserver

    The port number to start the service on, based on your requirements.

    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 of KMS, which must be the same as the video's region.
            String region = "cn-beijing";
            // AccessKey information for accessing KMS.
            // An AccessKey pair of an Alibaba Cloud account has full permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M.
            // To protect your resources, do not hardcode the AccessKey ID and AccessKey secret in your project code. Leaked AccessKey pairs may compromise the security of all your resources.
            // This example demonstrates how to use environment variables to obtain the AccessKey pair for identity verification. Before you run the code, configure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.
            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 to get the ciphertext key and token.
         * 2. Call the KMS decrypt API to get the plaintext key.
         * 3. Return the Base64-decoded plaintext key.
         */
        public class HlsDecryptHandler implements HttpHandler {
            /**
             * Handle the decryption request.
             * @param httpExchange
             * @throws IOException
             */
            public void handle(HttpExchange httpExchange) throws IOException {
                String requestMethod = httpExchange.getRequestMethod();
                if ("GET".equalsIgnoreCase(requestMethod)) {
    
                    // Get the ciphertext key from the URL.
                    String ciphertext = getCiphertext(httpExchange);
                    System.out.println(ciphertext);
                    if (null == ciphertext)
                        return;
                    // Decrypt from KMS and Base64 decode.
                    byte[] key = decrypt(ciphertext);
                    // Set the header.
                    setHeader(httpExchange, key);
                    // Return the base64decode key.
                    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 KMS decrypt API and Base64 decode the plaintext.
             * @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: The plaintext needs to be Base64-decoded.
                    return Base64.decodeBase64(plaintext);
                } catch (ClientException e) {
                    e.printStackTrace();
                    return null;
                }
            }
    
            /**
             * Get the ciphertext key parameter from the 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();
            // The listening port can be customized. It can handle up to 30 requests simultaneously.
            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.

    Call the GetVideoPlayAuth operation to get the playback credential or call the GetPlayInfo operation to get the playback URL.

  3. Play the encrypted video.

    HLS encryption is compatible with all HLS players. You can use your own player or ApsaraVideo Player to play the encrypted video.

    If you use ApsaraVideo Player, you must obtain a token and authentication information required by the player before starting playback. For more information, see Play encrypted videos. If you use a player other than ApsaraVideo Player, you must implement your own playback logic.

    The following section describes the internal workflow for playback with ApsaraVideo Player:

    Without rewrite

    Workflow

    • The player parses the EXT-X-KEY tag in the M3U8 file to obtain the decryption key URI, which is the value of the DecryptKeyUri parameter in EncryptConfig.

    • The player requests the decryption endpoint to get the key, decrypts the TS files, and plays the video.

    Example

    • The playback URL for the video 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 decryption request URL is: https://demo.aliyundoc.com?CipherText=ZjJmZGViNzUtZWY1Mi00Y2RlLTk3MTMtOT****

Related topics