Skip to main content

Widevine Common Encryption Sample Code

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);
}