Widevine Common Encryption Samples
Table of Contents
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);
}