Source code samples showing how to prepare a send a request to a Key Service using Widevine Common Encryption protocol.

Widevine Common Encryption Samples

This is a sample code to acquire encryption keys from Axinom DRM Key Service using Widevine Common Encryption protocol.

Setup

The following request JSON will be used in all samples below. Note that the contentId must be base64-encoded using your language of choice.

const contentId = "CID:"+ "123"; // alternatively use a GUID, e.g., "60f283e7-a423-44b8-9b1d-1f1ed7c03363" - then for all tracks the same key will be returned with the keyId=contentId
const widevineRequest =
{
    "content_id": Buffer.from(contentId).toString('base64'),
    "drm_types": [
      "WIDEVINE",
      "PLAYREADY",
      "FAIRPLAY"
    ],
    "tracks": [
      {"type": "AUDIO"},
      {"type": "SD"},
      {"type": "HD"},
      {"type": "UHD1"},
      {"type": "UHD2"}
    ],
    "protection_scheme": "CENC"
}

JavaScript/TypeScript / NodeJS

This example uses superagent to send HTTP requests and the crypto package built-in to NodeJS.

const superagent = require('superagent');
const crypto = require('crypto');

export async function invokeWidevineCommonEncryption() {
    const widevineResponse : object = await executeRequest(widevineRequest);
    console.log(JSON.stringify(widevineResponse,null,2));
}

/**
 * Execute a request against the Axinom DRM Key Service using Widevine Common Encryption endpoint
 * @param widevineRequest - the request object (JSON)
 * @returns widevineResponse (JSON)
 */
async function executeRequest(widevineRequest : object) : Promise<object> {

    const MOSAIC_KEY_SERVICE_ENDPOINT = 'https://key-server-management.axprod.net/api/WidevineProtectionInfo';
    const MOSAIC_KEY_PROVIDER_NAME = process.env.MOSAIC_KEY_PROVIDER_NAME; // get from Axinom DRM Key Service configuration
    const MOSAIC_KEY_SIGNING_KEY = process.env.MOSAIC_KEY_SIGNING_KEY; // get from Axinom DRM Key Service configuration
    const MOSAIC_KEY_SIGNING_IV = process.env.MOSAIC_KEY_SIGNING_IV; // get from Axinom DRM Key Service configuration
    if(!MOSAIC_KEY_SIGNING_KEY) throw new Error('MOSAIC_KEY_SIGNING_KEY is not set');
    if(!MOSAIC_KEY_SIGNING_IV) throw new Error('MOSAIC_KEY_SIGNING_IV is not set');

    // transform JSON to plain text
    const requestText = JSON.stringify(widevineRequest, null, 2);

    // Compute the signature
    // Compute the SHA1-hash of the request
    const sha1Hash = crypto.createHash('sha1').update(requestText).digest();
    // Encrypt the calculated SHA1-hash using AES-CBC using a 32-byte key (MOSAIC_KEY_SIGNING_KEY) and a 16-byte IV (MOSAIC_KEY_SIGNING_IV).
    const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(MOSAIC_KEY_SIGNING_KEY, 'hex'), Buffer.from(MOSAIC_KEY_SIGNING_IV, 'hex'));
    const encrypted = Buffer.concat([cipher.update(sha1Hash), cipher.final()]);
    // Apply base64-encode
    const signature = encrypted.toString('base64');

    const widevineEnvelope =
    {
        "request": Buffer.from(requestText).toString('base64'),
        "signature": signature,
        "signer": MOSAIC_KEY_PROVIDER_NAME
    };

    // console.log(JSON.stringify(widevineEnvelope, null, 2));

    // send a request to the Key Service
    const response = await superagent
        .post(MOSAIC_KEY_SERVICE_ENDPOINT)
        .set('Content-Type', 'application/json')
        .set('Accept', 'application/json')
        .send(widevineEnvelope);

    // response is a JSON object with a signle property "response" containing the base64-encoded JSON response
    const responseBase64 = response.body.response;
    // decode the base64-encoded response
    const responseText = Buffer.from(responseBase64, 'base64').toString('utf-8');
    // return as JSON
    return JSON.parse(responseText);
}