Widevine Common Encryption
Widevine Common Encryption is one of the most widespread Content Key exchange protocols. Many encryption tools and encoders (for example, Shaka Packager) support it.
Axinom Key Service implements Widevine Common Encryption protocol providing the
endpoint /WidevineProtectionInfo
of the Key Acquisition API.
See also:
- Online tool for signing and executing Widevine Common Encryption requests
- Widevine Common Encryption Sample Code
Functionalityβ
The Client requests one or more content keys. The Key Service generates the necessary keys using the Key Seed model and returns the keys with additional DRM-specific metadata where needed.
The Client shall send a single request for each video. If the video has multiple tracks (bitrates), different keys can be requested for each quality group (AUDIO, SD, HD, UHD1, UHD2).
The Key Service supports the following DRM technologies: Widevine, FairPlay, and PlayReady and the following protection schemes: CENC, CBC1, CENS, CBCS.
The following information is provided for each generated key:
- Key ID - can be set by the Client or randomly generated by the Key Service
- Key value - generated by the Key Service based on the default Key Seed
- IV - random initialization vector, needed for FairPlay
- PSSH Box - can be used by encoder to add to the output stream, see also PSSH article
- SKD URI - used by FairPlay
- Checksum - used by PlayReady
Authorizationβ
Instead of using an HTTP header for authentication, you have to sign each request using your signing credentials as described under Request Signing below. The signing credentials include:
- Provider Name
- Signing Key
- Signing IV (initialization vector)
You can get these values from Axinom Portal, providing your Management Key:
Signing credentials on Axinom Portal
WidevineProtectionInfoCredentialsβ
Additionally, you can manage the signing credentials programmatically using the endpoint /WidevineProtectionInfoCredentials
.
It exposes a collection of the signing credentials sets. Initially, you have just one.
But you can create a new one or change the values for the existing credentials and even delete them.
To create new singning credentials send a POST to /WidevineProtectionInfoCredentials
with the following payload (the values base64-encoded):
{
"ProviderName": "sample string 1",
"SigningKey": "QEA=",
"SigningIv": "QEA="
}
This endpoint requires an authorization header - the same as described under the
Key Service Management API, i.e. you will need your tenantID
and managementKey
.
Request/Response Formatβ
Widevine Content Key Requestβ
The Client provides the input parameters in a JSON data structure called the Widevine Content Key Request:
{
"content_id": "MEIzNTBDMDgtNEJDQi00Qjk2LUE4NzMtOEMyNEY2RTk5MUM1",
"drm_types": [
"WIDEVINE",
"PLAYREADY",
"FAIRPLAY"
],
"tracks": [
{"type": "AUDIO"},
{"type": "SD"},
{"type": "HD"},
{"type": "UHD1"},
{"type": "UHD2"}
],
"protection_scheme": "CENC"
}
The table below outlines the elements of the Content Key request JSON above.
Element | Description |
---|---|
content_id | Content ID, base64-encoded |
drm_types | Requested DRM types, possible values: WIDEVINE, FAIRPLAY, PLAYREADY. Optional. Default - Widevine only. |
tracks | Array of the video tracks with their respective type (=Quality Group). Supported types: AUDIO, SD, HD, UHD1,UHD2. At least one track is required. |
protection_scheme | Protection scheme to use. Supported values: CENC, CBC1, CENS, CBCS. Optional. Default - CENC. |
The Content ID can be:
- A GUID, presented as a string in the format
00000000-0000-0000-0000-000000000000
. In this case, all tracks have the same Content Key. Its Key ID matches the provided Content ID. - Any string, prefixed with "CID:", e.g. "CID:Batman". In this case, every track has its own Content Key with a random Key ID.
Widevine Content Key Responseβ
The Key Service provides a response as a JSON data structure called the Widevine Content Key Response. It is very similar to the Widevine Content Key Request, but it is extended with the generated key material:
{
"status": "OK",
"content_id": "MEIzNTBDMDgtNEJDQi00Qjk2LUE4NzMtOEMyNEY2RTk5MUM1",
"drm": [
{"type": "WIDEVINE", "system_id": "edef8ba979d64acea3c827dcd51d21ed"},
{"type": "PLAYREADY", "system_id": "9a04f07998404286ab92e65be0885f95"},
{"type": "FAIRPLAY", "system_id": "29701fe43cc74a348c5bae90c7439a47"}
],
"tracks": [
...
{
"type": "HD",
"key_id": "CzUMCEvLS5aoc4wk9umRxQ==",
"key": "xL/zgE8V9fjPEdqQse5NIA==",
"iv": "Bc2m8UG/rpC/eTDuacmtSw==",
"skd_uri": "skd://0b350c08-4bcb-4b96-a873-8c24f6e991c5:05CDA6F141BFAE90BF7930EE69C9AD4B",
"checksum": "jmiyKlynsq4=",
"pssh": [
{"drm_type": "WIDEVINE", "data": "EhAL...WbBg=="},
{"drm_type": "PLAYREADY", "data": "xAE...gA="},
{"drm_type": "FAIRPLAY", "data": ""}
]
},
...
]
}
The table below explains the elements of the Content Key response JSON:
Element | Description |
---|---|
status | Status code. The possible values are: "OK" , "SIGNATURE_FAILED" , "CONTENT_ID_MISSING" , "POLICY_UNKNOWN" , "TRACK_TYPE_MISSING" , "TRACK_TYPE_UNKNOWN" , "MALFORMED_REQUEST" |
content_id | Same value as in the respective request. |
drm | List of the DRM systems for which the keys are generated according to the request. Contains a type and a system_id (GUID) for each DRM |
tracks | Array of the video tracks according to the request with their respective type (=Quality Group) and generated key information |
key_id | Key ID of the Content Key, base64-encoded GUID, serialized as a byte array in a big endian byte order. For example, the following byte array - 0B350C084BCB4B96A8738C24F6E991C5 - shall result in the following GUID: 0B350C08-4BCB-4B96-A873-8C24F6E991C5. If the content_id is a GUID, all key_ids are equal to it. Otherwise, all key_ids are different and random |
key | Generated Content Key as a base64-encoded byte array. |
iv | Randomly generated Initialization Vector (IV) for the Content Key. An explicit IV is generated only for FairPlay, but even for FairPlay the IV can be generated by the encoder, thus overriding this IV. |
skd_uri | Axinom DRM FairPlay License Service specific Streaming Key Delivery (SKD) URI to be included in the HLS playlist file. A string in the format skd://[KeyID]:[IV] where [Key ID] is a GUID in its string representation and [IV] is a 16-byte array in hex encoding. This field is only generated if FairPlay is requested. Additionally, the :[IV] part of the SKD URI may be omitted when using the Axinom DRM License Service for License Acquisition |
checksum | PlayReady Content Key ID/Content Key checksum, as an 8-byte array in base64 encoding. This field is only generated if PlayReady is requested, but it doesnβt have to be used, not even for PlayReady |
pssh | PSSH Box for PlayReady and Widevine (not available for FairPlay). The data-field is base64-encoded. See also PSSH article. |
Envelopeβ
Before the Widevine Content Key Request goes on the wire, it shall be wrapped in an "envelope" - a JSON data structure called Widevine Request:
{
"request": "eyJjb250ZW50X2lkIjoiTUVJek5UQkRNRGd0TkVKRFFpMDBRamsyTFVFNE56TXRPRU15TkVZMlJUazVNVU0xIiwidHJhY2tzIjpbeyJ0eXBlIjoiQVVESU8ifSx7InR5cGUiOiJTRCJ9LHsidHlwZSI6IkhEIn1dfQ==",
"signature": "kpn8s1kS0GVexoCRz1vc6Bxn833Y2wEQDZofugGpcDU=",
"signer": "widevine_test"
}
The elements of the JSON envelope are described in the table below.
Element | Description |
---|---|
request | base64-encoded Widevine Content Key Request (the payload) |
signature | A signature for the request, serving as an authentication mechanism for the Client. See Request Signing below |
signer | A signer name - each Tenant of the Axinom Key Service gets a Widevine Provider Name assigned that shall be used as a Signer. |
The Key Service response - the Widevine Content Key Response - is wrapped into a JSON data structure called the Widevine Response:
{
"response": "eyJzdGF0dXMiOiJPSyIsImNvbnRlbnRfaWQiOiIwQjM1MEMwOC00QkNCLTRCOTYtQTg3My04QzI0RjZFOTkxQzUiLCJkcm0iOlt7InR5cGUiOiJXSURFVklORSIsInN5c3RlbV9pZCI6ImVkZWY4YmE5LTc5ZDYtNGFjZS1hM2M4LTI3ZGNkNTFkMjFlZCJ9XSwidHJhY2tzIjpbeyJwc3NoIjpbeyJkcm1fdHlwZSI6IldJREVWSU5FIiwiZGF0YSI6IkNBRVNFQXMxREFoTHkwdVdxSE9NSlBicGtjVWFEWGRwWkdWMmFXNWxYM1JsYzNRaUpEQkNNelV3UXpBNExUUkNRMEl0TkVJNU5pMUJPRGN6TFRoRE1qUkdOa1U1T1RGRE5Tb0ZRVlZFU1U4PSJ9XSwia2V5X2lkIjoiQ3pVTUNFdkxTNWFvYzR3azl1bVJ4UT09IiwidHlwZSI6IkFVRElPIiwia2V5IjoieEwvemdFOFY5ZmpQRWRxUXNlNU5JQT09In0seyJwc3NoIjpbeyJkcm1fdHlwZSI6IldJREVWSU5FIiwiZGF0YSI6IkNBRVNFQXMxREFoTHkwdVdxSE9NSlBicGtjVWFEWGRwWkdWMmFXNWxYM1JsYzNRaUpEQkNNelV3UXpBNExUUkNRMEl0TkVJNU5pMUJPRGN6TFRoRE1qUkdOa1U1T1RGRE5Tb0NVMFE9In1dLCJrZXlfaWQiOiJDelVNQ0V2TFM1YW9jNHdrOXVtUnhRPT0iLCJ0eXBlIjoiU0QiLCJrZXkiOiJ4TC96Z0U4VjlmalBFZHFRc2U1TklBPT0ifSx7InBzc2giOlt7ImRybV90eXBlIjoiV0lERVZJTkUiLCJkYXRhIjoiQ0FFU0VBczFEQWhMeTB1V3FIT01KUGJwa2NVYURYZHBaR1YyYVc1bFgzUmxjM1FpSkRCQ016VXdRekE0TFRSQ1EwSXRORUk1TmkxQk9EY3pMVGhETWpSR05rVTVPVEZETlNvQ1NFUT0ifV0sImtleV9pZCI6IkN6VU1DRXZMUzVhb2M0d2s5dW1SeFE9PSIsInR5cGUiOiJIRCIsImtleSI6InhML3pnRThWOWZqUEVkcVFzZTVOSUE9PSJ9XX0="
}
The "response"
is a base64-encoded Widevine Content Key Response (the payload).
Request Signingβ
To calculate the signature:
- Compute the SHA1-hash of the Widevine Content Key Request (before applying base64 to it).
- Encrypt the calculated SHA1-hash using AES-CBC using a 32-byte key and a 16-byte IV. Each Tenant of the Axinom Key Service gets a Widevine Signing Key and Widevine Signing IV assigned for this purpose.
- Apply base64-encode
Resourcesβ
- Online tool for signing and executing Widevine Common Encryption requests
- Code sample in JavaScript
Encryption Schemesβ
An encryption scheme can be specified with the element protection_scheme
.
Supported values are CENC, CBCS, CENS, CBC1. But depending on the DRM technology, it may fall back to a default value if the specified value is not supported.
Values supported for 'protection_scheme' their mapping to the DRM technologies. Defaults are in brackets.
Scheme | Widevine | PlayReady | FairPlay |
---|---|---|---|
CENC | (CENC) | (CENC) | CBCS |
CBCS | CBCS | CBCS | (CBCS) |
CENS | CENS | CENC | CBCS |
CBC1 | CBC1 | CENC | CBCS |
WidevineProtectionInfoConfigurationβ
You can configure the behavior of the /WidevineProtectionInfo
endpoint by setting configuration parameters using the
/WidevineProtectionInfoConfiguration
endpoint.
It supports both - GET and POST. GET for reading the current values, POST - for settings the values.
This endpoint requires an authorization header - the same as described under the
Key Service Management API, i.e. you will need your tenantID
and managementKey
.
{
"PlayReadyLaUrl": "https://drm-playready-licensing.axprod.net/AcquireLicense"
}
The following parameters are currently supported:
- PlayReadyLaUrl
PlayReady License Acquisition URL for the PSSH Boxβ
PSSH box included in the protected video contains some metadata about the applied protection. A part of this data structure is a License Acquisition URL. In most cases, it is not relevant, because the Player can use any configured License Acquisition URL. But there are some PlayReady Player implementations that rely on the License Acquisition URL delivered as a part of the PSSH Box.
To support such Players, Axinom Key Service allows configuring the License Acquisition URL.
A part of the PSSH box for PlayReady contains a PlayReady header, which contains the License Acquisition URL in the following way:
<WRMHEADER xmlns="https://schemas.microsoft.com/drm/2007/03/PlayReadyHeader" version="4.0.0.0">
<DATA>
<PROTECTINFO>
<ALGID>AESCTR</ALGID>
<KEYLEN>16</KEYLEN>
</PROTECTINFO>
<KID>q5HgCTj40kGeNVhTH9Gexw==</KID>
<LA_URL>https://drm-playready-licensing.axprod.net/AcquireLicense</LA_URL>
</DATA>
</WRMHEADER>
LA_URL
is not present unless it is previously set using the /WidevineProtectionInfoConfiguration
endpoint.
To read more about PlayReady headers, follow this link: https://docs.microsoft.com/en-us/playready/specifications/playready-header-specification.
Putting it all Togetherβ
Below are the steps to get a key from the Axinom Key Service using the Widevine Common Encryption protocol.
We assume here that:
- the Content ID is
"CID:Batman"
- there are 3 tracks: Audio, SD, and HD
- each track will be protected with its own content key
- only Widevine is in use
- a default protection scheme is applicable
-
Create a Widevine Content Key Request:
{
"content_id": "Q0lEOkJhdG1hbg==",
"tracks": [
{"type": "AUDIO"},
{"type": "SD"},
{"type": "HD"}
]
} -
Calculate the signature as described in Request Signing above.
-
Compose the Widevine Request:
{
"request": "<base64(Widevine Content Key Request)>",
"signature": "<Calculated Signature(Widevine Content Key Request, Widevine Signing Key, Widevine Signing IV)>",
"signer": "<Widevine Provider Name>"
} -
Send the Widevine Request to the Axinom Key Service:
POST <Key Service API>/api/WidevineProtectionInfo
<Widevine Request> -
If everything is done correctly, you get a Widevine Response with an HTTP code 200:
{
"response": "<Widevine Content Key Response as base64>"
} -
Base64-decode the response.
-
For each track, extract the
key_id
andkey
elements and base64-decode them.
-
The online-tools under My DRM will help you.
Differences Between Axinom and Google Implementationsβ
Google provides its own implementation of the Widevine Common Encryption protocol in the Widevine Cloud Service.
There are a few differences with the Axinom implementation:
- Google Service supports only Widevine
- Axinom uses the Key Seed Model
- Axinom applies a naming convention for the
content_id
(see above) - Google Service supports some additional features