License Cipher SDK Guide

Overview

This guide explains DRM License Cipher SDK, which enhances the security of software-level Widevine L3 DRM.

Widevine L3 DRM, which provides software-level security, has the disadvantage of being vulnerable to hacking compared to Widevine L1, which supports hardware security based on the Trusted Execution Environment (TEE). When playing Widevine DRM content in Android or web applications, the License Cipher SDK can be applied to encrypt DRM license requests to prevent content key leakage by various hacking tools.

By applying the app security features of AppSealing Service along with License Cipher, you can effectively block hacking attempts on your Android app to enhance content security.

Prerequisites

To use the License Cipher SDK, you’ll need the following:

  • Enterprise plan and AppSealing service subscription
    • To use License Cipher, you need to subscribe to PallyCon Enterprise plan. You also need to subscribe to AppSealing service to apply application security.
    • The same conditions apply if you integrate with a third-party player instead of PallyCon Widevine Android SDK.
  • Request License Cipher SDK
    • The License Cipher SDK is delivered through our Helpdesk. To request this SDK, please create a ticket on the Helpdesk website.
  • Using PallyCon Widevine Android SDK or a compatible third-party player
    • In addition to PallyCon Widevine Android SDK, the License Cipher SDK works with Google ExoPlayer or Bitmovin player.
    • If you need to integrate License Cipher SDK with other player solutions, please contact our Helpdesk.
  • Download the key table file
    • You need to download the WhiteBox Crypto (WBC) key table used for encryption of license request data from PallyCon Console. (Multi DRM > DRM Setting > License Cipher)
    • The downloaded key table file should be included in the Android app where you want to apply License Cipher.

Android License Cipher SDK

PallyCon License Cipher SDK for Android works in the following ways, depending on the integration target. For more information on both integrations, please refer to the sample projects included with the SDK.

Integrating with PallyCon Widevine Android SDK

  1. Copy the key table file downloaded from PallyCon Console to the assets folder of your Android application project.
  2. Unzip the License Cipher SDK delivered through the Helpdesk.
  3. Copy the PallyConLicenseCipher.aar file to the /module/libs/ folder of your project.
  4. Add the following settings to build.gradle (app).
dependencies {
  ...
  // If the pallycon widevine sdk is included in the existing 'project/module/libs/', omit it.
  implementation 'com.pallycon:widevine:x.x.x' 

  implementation fileTree(dir: 'libs', include: ['*.aar'])
  ...
}
  1. In the DRM configuration of the Widevine Android SDK, add the key table path as follows.
// Enter DRM-related information.
val config = PallyConDrmConfiguration(
 siteId = "site id",
 customData = "content auth data",
 httpHeaders = mutableMapOf(), // custom header
 drmLicenseUrl = "request license server url",
 licenseCipherPath = "key table file path in assets" // ex) plc-kt-test.bin
)

val data = ContentData(
 contentId = "content id",
 url = "content URL",
 localPath = "Download location where content will be stored",
 drmConfig = config,
 cookie = null
)

val wvSDK = PallyConWvSDK.createPallyConWvSDK(
 Context, // Context
 data
)

Integrating with 3rd party player solutions

  1. Copy the key table file downloaded from PallyCon Console to the assets folder of your Android application project.
  2. Unzip the License Cipher SDK delivered through the Helpdesk.
  3. Copy the PallyConLicenseCipher.aar file to the /module/libs/ folder of your project.
  4. Add the following settings to build.gradle (app).
dependencies {
  ...
  // If the pallycon widevine sdk is included in the existing 'project/module/libs/', omit it.
  implementation 'com.pallycon:widevine:x.x.x' 

  implementation fileTree(dir: 'libs', include: ['*.aar'])
  ...
}
  1. Import License Cipher library.
import com.pallycon.licensecipher.LicenseCipher
  1. When requesting a Widevine license, encrypt the request data using License Cipher.
// If you use ExoPlayer, you will need to inherit the 'MediaDrmCallback' and implement your own license request process. 
// licenseData is the widevine request license data and the data type is ByteArray.
val outputData = ByteArray(licenseData.size)
// create license cipher, path = The path to the Asset directory. ex) plc-kt-test.bin
// You can download the table file from the PallyCon console.
val licenseCipher = LicenseCipher.createLicenseCipher(context, tablePath)
// doCipher
if (licenseCipher.doCipher(licenseData, outputData)) {
  // requestData is the data to include in the body when communicating with the server API.
  requestData = outputData
}
To integrate the License Cipher SDK with a third-party player solution, the player needs to provide a callback API for DRM license requests. In the case of Google ExoPlayer, this is supported via the MediaDrmCallback interface, and some commercial player solutions may provide similar APIs. (e.g. Bitmovin Player)

Chrome License Cipher SDK

PallyCon License Cipher SDK for Chrome helps prevent Widevine key leakage in web applications. The SDK is implemented in JavaScript and WebAssembly, and it can be integrated with any HTML5 player that supports a callback interface for DRM license requests.

The SDK consists of the following modules:

  • DRMLicenseCipher.js: JavaScript file that implements the encryption of Widevine license request data (challenge). Obfuscated for security purposes.
  • wbwflea.wasm: White Box Crypto (WBC) module used to secure cryptographic keys. Implemented with WebAssembly.

Applying Chrome License Cipher

The SDK can be applied to your web application by following the steps below.

  1. Upload SDK modules to your server
  • Upload the SDK modules (.js, .wasm files) to a web server operated by your service. The two files must be located on the same path.
  • You must be able to link to the DRMLicenseCipher.js file from your web application.
  1. Add the JS module link
  • In the HTML code of your web application, add a link to the corresponding JS file as follows.
    <script src="DRMLicenseCipher.js"></script>
    
  1. Initialize License Cipher module
  • On web page load, the following code creates and initializes the License Cipher module.
  • Handle events for errors and status that occur in the module as needed.
  • The input value of the prepareEncryption function uses the Site ID (four-digit alphanumeric) assigned to the customer’s PallyCon service account.
    // Create a DRMLicenseCipher instance
    const drmCipher = new DRMLicenseCipher();
    
    // Register an event
    drmCipher.on('PallyConError', (event) => {
        console.error('Error event received:', event);
    });
    
    drmCipher.on('PallyConState', (event) => {
        console.log('State event received:', event);
    });
    
    drmCipher.on('DownloadProgress', (event) => {
        console.log('Download progress:', event);
    });
    
    // Preparing for encryption
    async function prepareEncryption(siteId) {
        const isPrepared = await drmCipher.prepare(siteId);
        if (isPrepared) {
            console.log('Encryption preparation successful.');
        } else {
            console.error('Encryption preparation failed.');
        }
    }
    
Within the prepareEncryption function, the WBC key table file for the entered site ID value is automatically downloaded from the PallyCon server on the first run. Afterward, the key table cached in the browser’s local storage is used.
  1. Encrypt the DRM license request
  • Encrypt the request data (body) with the License Cipher module using DRM license request callback API provided by HTML5 player.
  • The following is an example implemented with the API supported by Shaka Player. The implementation of the callback API may vary depending on the player solution.
    player.getNetworkingEngine().registerRequestFilter(async function (type, request) {
        if (type == shaka.net.NetworkingEngine.RequestType.LICENSE) {
            request.headers['pallycon-customdata-v2'] = customdata;
            if (request.body.byteLength > 3) {
                const encodedData = arrayBufferToBase64(request.body);
                const responseData = await cipher.encryptData(encodedData);
                const decodedData = base64ToArrayBuffer(responseData);
                request.body = decodedData;
            }
        }
    });
    
  1. Resetting data and releasing the module
  • After encrypting license request data, reset and release the License Cipher module in the following ways
    // Data reset
    async function resetData() {
        const isReset = await drmCipher.reset();
        if (isReset) {
            console.log('Data reset successful.');
        } else {
            console.error('Data reset failed.');
        }
    }
    
    // Data release
    async function releaseData() {
        const isReleased = await drmCipher.release();
        if (isReleased) {
            console.log('Data release successful.');
        } else {
            console.error('Data release failed.');
        }
    }
    

For detailed implementation, please refer to the sample page (based on Shaka Player) included in the SDK.

Applying License Cipher option to license token

After you apply the License Cipher feature to a client app, enable the encryption flag on the license token used by that app, as shown in the example below.

"security_policy": [
  {
    ...
    "widevine": {
      ...
      "enable_license_cipher": true
    },
    ...
  }
]

This flag should only be set to true for versions of Android apps with the License Cipher SDK, and for other versions of Android apps, browsers, and other clients (such as smart TVs) where license request data is not encrypted, the flag should be omitted or set to false.

If the value of the enable_license_cipher setting and the actual encryption of the license request data do not match, the server will fail to process it, resulting in a license issuance error.

Blocking unencrypted requests

After you apply the License Cipher feature to a client app, you need to block unencrypted requests so that only license requests from that app are allowed. Set up blocking in the following ways, depending on your case of adopting the feature.

Adopting License Cipher to a new service

If you’re applying License Cipher to a new service, you can block unencrypted license requests when the client app with License Cipher is registered on the store.

  1. Log in to PallyCon Console.
  2. Change the Allow or block unencrypted license requests option on Multi-DRM > DRM Setting > License Cipher section to Block.

After the above settings, Widevine license requests from Android apps will only be processed normally if they are encrypted via the License Cipher SDK, and unencrypted requests will be treated as hacking attempts and DRM license issuance will be denied.

Currently, the License Cipher feature is only available for Android apps, not web browsers or other client environments. Therefore, the Allow or block unencrypted license requests option also only applies to requests from Android apps, and unencrypted requests from other clients will be allowed to issue licenses regardless of the option.

Adopting License Cipher to an existing service

If you’re already serving DRM content, to minimize user disruption during the introduction of License Cipher solution, you should allow unencrypted requests from older versions of your app until most users update to the new version of your app.

  1. Apply the License Cipher SDK to your client app
  2. Set the enable_license_cipher flag in the token specification to true for the new version of the app (default: false)
  3. Register the updated app on the store and notify users for the update.
  4. Change the Allow or block unencrypted license requests option to Block in PallyCon Console when most users have completed the update.

Integrating with License Proxy Server

If you are integrating DRM licenses through a proxy server operated in your system, you need to set the enable_license_cipher item to true in the license token generated by the proxy, depending on the client environment. (Only for Android apps with License Cipher SDK applied)

The passing of request data and response data between the license server and the client, which is handled by the proxy server, is done in the same way as before, regardless of whether License Cipher is applied or not.

Previous
Next