Skip to main content

Harmonic

Axinom Key Service supports direct integration with the Harmonic encoder that provides support for the H.264 and H.265 video codecs.

The integration endpoint is /Harmonic/v2 of the Key Acquisition API.

note

The previous version of this endpoint, /Harmonic still exists for backward compatibility. It used a different keyID derivation algorithm, hence the new node is not backward compatible, i.e. even the same content encoded again using the new endpoint will receive different keys. But for all new scenarios it is recommended to use the v2. Other limitations of the previous version:

  • Missing Multi-key and Key-rotation support
  • The attribute commonEncryptionScheme of the element cpix:ContentKey is not supported (see Encryption Schemes below).

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.

Harmonic - Request/Response

Authorization​

This endpoint requires an authorization header - the same as described under the Key Service Management API.

Request/Response Format​

Request​

The Client creates a CPIX document in the format which it desires to get, just without the values for the keys, and sends this document to the Key Service. The Key Service generates the specified keys, adds this information to the document, and returns the CPIX document to the Client.

Example of a Harmonic Request (CPIX)

<?xml version="1.0" ?>
<cpix:CPIX contentId="channel_01" xmlns:cpix="urn:dashif:org:cpix">
<cpix:ContentKeyList>
<cpix:ContentKey kid="af1ed63c-5784-460b-9e51-309dd47b7d9c"/>
</cpix:ContentKeyList>
<cpix:DRMSystemList>
<cpix:DRMSystem kid="af1ed63c-5784-460b-9e51-309dd47b7d9c" systemId="94ce86fb-07ff-4f43-adb8-93d2fa968ca2"/>
<cpix:DRMSystem kid="af1ed63c-5784-460b-9e51-309dd47b7d9c" systemId="9a04f079-9840-4286-ab92-e65be0885f95"/>
<cpix:DRMSystem kid="af1ed63c-5784-460b-9e51-309dd47b7d9c" systemId="edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
</cpix:DRMSystemList>
<cpix:ContentKeyPeriodList>
<cpix:ContentKeyPeriod start="2023-04-17T00:00:00Z" end="2024-02-17T16:55:00Z" id="keyperiod_1608224040"/>
</cpix:ContentKeyPeriodList>
<cpix:ContentKeyUsageRuleList>
<cpix:ContentKeyUsageRule intendedTrackType="audio" kid="af1ed63c-5784-460b-9e51-309dd47b7d9c">
<cpix:KeyPeriodFilter periodId="keyperiod_1608224040"/>
<cpix:AudioFilter/>
</cpix:ContentKeyUsageRule>
</cpix:ContentKeyUsageRuleList>
</cpix:CPIX>

The table below explains some important elements of the request XML.

ElementPurpose
ContentKeyListThe list of the Key IDs for which the Keys shall be generated. Each key ID is a GUID.
DRMSystemListRequested DRM types, for which the PSSH boxes will be delivered. The IDs are as defined by DASH-IF. Axinom Key Service supports FairPlay, PlayReady, and Widevine (listed in the example above in this order).
ContentKeyPeriodListList of ContentKeyPeriod elements.
ContentKeyUsageRuleListContent key usage rules for each key. It’s a pass-through that will only be returned to the Client.

Response​

The response is a CPIX document.

Example CPIX document returned by the '/Harmonic' endpoint
<?xml version="1.0" encoding="utf-8"?>
<cpix:CPIX contentId="channel_01" xmlns:cpix="urn:dashif:org:cpix">
<cpix:ContentKeyList>
<cpix:ContentKey kid="8b5a0f76-1725-92b3-07d4-f563ca483b0d" explicitIV="50X3FbzWRUZNwBKVnH7EIQ==">
<cpix:Data>
<Secret xmlns="urn:ietf:params:xml:ns:keyprov:pskc">
<PlainValue>kusV8szSsx5HfjjT3Jt+Ew==</PlainValue>
</Secret>
</cpix:Data>
</cpix:ContentKey>
</cpix:ContentKeyList>
<cpix:DRMSystemList>
<cpix:DRMSystem systemId="9a04f079-9840-4286-ab92-e65be0885f95" kid="8b5a0f76-1725-92b3-07d4-f563ca483b0d">
<cpix:HLSsignallingData playlist="master">I0VYVC1YLVNFU1NJT04tS0VZOk1FVEhPRD1TQU1QTEUtQUVTLFVSST0ic2tkOi8vOGI1YTBmNzYtMTcyNS05MmIzLTA3ZDQtZjU2M2NhNDgzYjBkOkU3NDVGNzE1QkNENjQ1NDY0REMwMTI5NTlDN0VDNDIxIixLRVlGT1JNQVQ9ImNvbS5hcHBsZS5zdHJlYW1pbmdrZXlkZWxpdmVyeSIsS0VZRk9STUFUVkVSU0lPTlM9IjEi</cpix:HLSsignallingData>
<cpix:HLSsignallingData playlist="media">I0VYVC1YLUtFWTpNRVRIT0Q9U0FNUExFLUFFUyxVUkk9InNrZDovLzhiNWEwZjc2LTE3MjUtOTJiMy0wN2Q0LWY1NjNjYTQ4M2IwZDpFNzQ1RjcxNUJDRDY0NTQ2NERDMDEyOTU5QzdFQzQyMSIsS0VZRk9STUFUPSJjb20uYXBwbGUuc3RyZWFtaW5na2V5ZGVsaXZlcnkiLEtFWUZPUk1BVFZFUlNJT05TPSIxIg==</cpix:HLSsignallingData>
</cpix:DRMSystem>
</cpix:DRMSystemList>
<cpix:ContentKeyPeriodList>
<cpix:ContentKeyPeriod end="2024-02-17T16:55:00Z" id="keyperiod_1608224040" start="2023-02-17T16:54:00Z" />
</cpix:ContentKeyPeriodList>
<cpix:ContentKeyUsageRuleList>
<cpix:ContentKeyUsageRule kid="8b5a0f76-1725-92b3-07d4-f563ca483b0d" intendedTrackType="audio">
<cpix:KeyPeriodFilter periodId="keyperiod_1608224040" />
<cpix:AudioFilter />
</cpix:ContentKeyUsageRule>
</cpix:ContentKeyUsageRuleList>
</cpix:CPIX>

The table below explains the key elements of the response XML.

ElementDescription
ContentKeyListA generated Key and an initialization vector (IV) for each Key ID
DRMSystemListAdditional protection data for each requested DRM system and each key
ContentKeyPeriodListList of ContentKeyPeriod elements.
ContentKeyUsageRuleListContent key usage rules, the same as in the request.
note

For configuring a PlayReady Header "LA_URL" in the returned signalling data, please refer to this guide

Encryption Schemes​

With the /Harmonic/v2 endpoint, the License Service supports an optional attribute commonEncryptionScheme for each requested key.

Values supported for 'commonEncryptionScheme' and each of the DRM technologies. Value in brackets is the default for a given technology.

SchemeWidevinePlayReadyFairPlay
cenc(X)(X)
cbcsXX(X)
censX
cbc1X
Caution

If you need FairPlay together with Widevine/PlayReady, you have to set commonEncryptionScheme explicitly to cbcs. Otherwise, different encryption schemes will be selected by default, breaking the keyID-override algorithm.

note

For the v1 endpoint, /Harmonic, the value of this attribute was not considered and the encryption scheme was always set to the defaults in the table above. The keyID-override algorithm didn’t take the encryption scheme into account, so the limitation above did not exist.

KeyID Override​

The keyID (attribute keyID) from the request CPIX is not used.

...
<cpix:ContentKey kid="af1ed63c-5784-460b-9e51-309dd47b7d9c"/>
...

Instead, the Key Service generates another keyID using a deterministic algorithm based on the provided contentID. While SPEKE endpoints supports enabling and disabling this feature, Harmonic endpoints will always override the key IDs and cannot be disabled.

Key Derivation for Harmonic V2​

Similar to the SPEKE endpoint, we take all input parameters that contribute to the uniqueness of the Key ID, compute a SHA-256 hash of them, and then XOR the first and second halves of the hash to reduce the output to 128 bits. The resulting 128-bit value is then converted into a GUID. However, note that the input parameters used in the algorithm differ between Harmonic and SPEKE.

Parameters used for Harmonic V2:

  • TenantId - Customer’s Axinom DRM Tenant ID (to be found under My Mosaic / DRM / Key Service configuration).

  • Content ID - The identifier of a video asset or a stream. In the request CPIX, it is the contentId attribute of the root cpix:CPIX.

  • Protection Scheme - The protection scheme used for the content key. This defaults to cenc for keys associated with Widevine and PlayReady, and to cbcs for FairPlay, unless otherwise specified in the CPIX request. Note that if a key is used for both FairPlay and other DRM technologies, the protection scheme will be cbcs due to FairPlay can only use CBCS protection scheme.

  • Intended Track Type - The track type of the key ID specified in the packager. This is typically VIDEO, AUDIO, HD, SD, etc., but it can be any string value defined by the packager. Please refer to the packager’s documentation for details. If no track type is defined, an empty string may be used.

  • Content Key Period Index - When the packager’s key rotation is enabled in Index mode, each CPIX key request includes a sequential period index number. In the Harmonic packager, this is typically a Unix timestamp. When key rotation is disabled, the key derivation algorithm will use an empty string.

  • Content Key Period Start - When the packager’s key rotation is enabled in Timestamp"** mode, this parameter is required for key derivation. It works in conjunction with the Key Period Interval parameter. The value is a Unix epoch timestamp that is floored to the nearest boundary based on the specified key period interval. For example, if the interval is 30 minutes, the key period start times will be precise 30-minute marks such as 01:00:00, 01:30:00, etc. If the interval is 10 minutes, the times would be 01:00:00, 01:10:00, 01:20:00, and so on. Note that this start time used in the algorithm may not align exactly with the actual CPIX request time. However, for practicality, the algorithm is designed to adjust to a predictable and consistent timestamp that is easy to work with.

  • Key Period Interval - This defines the key rotation duration in seconds. When the key period mode is set to Timestamp, this is a mandatory input.

It is recommended to use the Timestamp mode when key rotation is enabled. With our key derivation algorithm’s flooring mechanism, even if the packager sends an irregular start time (e.g., 01:03:10), the algorithm will adjust it to a clean boundary like 01:00:00. This approach allows customers to predict and provision the previous, current, and next Key IDs, enabling seamless playback.

However, when key rotation is enabled in Index mode, the index timestamp is not adjusted by us. As a result, it becomes difficult to predict the correct index without parsing the initial CPIX request.

The algorithm is as follows:

InputParameters = "<TenantId>" + "<Content ID>" + "<Protection Scheme>"+ "<Intended Track Type>" + [<Content Key Period Index>] or [<Content Key Period Start> + <Key Period Interval>]

BaseHash = SHA256(InputParameters)

PartOneHash = Take first 16 bytes of BaseHash

PartTwoHash = Take the last 16 bytes of BaseHash

XorResult = PartOneHash XOR PartTwoHash

Key ID = XorResult to GUID // GUID must be generated using little-endian byte order as in Microsoft .NET.

Sample Key IDs derived according to the algorithm​

For no key rotation:

ParameterValue
tenantId145ac0b6-ad3e-452d-8778-5c02033efea6
contentIdtest_content
protectionSchemecenc
intendedTrackTypeVIDEO
contentKeyPeriodIndexnull or empty string
contentKeyPeriodStartnull or empty string
keyPeriodIntervalnull or empty string
Expected Key ID0910abc5-0eb2-ad1d-10de-9e42337059bb


For index mode key rotation:

ParameterValue
tenantId145ac0b6-ad3e-452d-8778-5c02033efea6
contentIdtest_content
protectionSchemecenc
intendedTrackTypeVIDEO
contentKeyPeriodIndex1743445800
contentKeyPeriodStartnull or empty string
keyPeriodIntervalnull or empty string
Expected Key ID18368ea2-7441-e30c-a08d-b6b282731d8a


For timestamp mode key rotation:

ParameterValue
tenantId145ac0b6-ad3e-452d-8778-5c02033efea6
contentIdtest_content
protectionSchemecenc
intendedTrackTypeVIDEO
contentKeyPeriodIndexnull or empty string
contentKeyPeriodStart1743445800
keyPeriodInterval600
Expected Key ID15084cc0-fb55-0d66-7d5a-e55a9a94b354

Sample Key Derivation Algorithm Implementation in JavaScript/NodeJS​

const crypto = require("crypto");

const inputParameters = "145ac0b6-ad3e-452d-8778-5c02033efea6" + "test_content" + "cenc" + "VIDEO" + "1743445800" + "600";
var baseToHashAsByteser = Buffer.from(inputParameters);

// SHA256 hash
var sha256Hasher = crypto.createHash("sha256");
sha256Hasher.update(baseToHashAsByteser);
const baseHashValue = sha256Hasher.digest();

// XOR the first and second half of the base hash to make a 16 bytes hash
const partOne = baseHashValue.slice(0, 16);
const partTwo = baseHashValue.slice(16, 32);

let xorHash = Buffer.alloc(16);
for (let n = 0; n < 16; n++)
xorHash[n] = partOne[n] ^ partTwo[n % partTwo.length];

// Convert to a GUID (based on little-endian bytes)
const kid = createGUID(xorHash);

console.log(kid);

function createGUID(buffer) {
// mind the reverse endianess for the first three parts
return buffer.subarray(0, 4).reverse().toString('hex') + '-' +
buffer.subarray(4, 6).reverse().toString('hex') + '-' +
buffer.subarray(6, 8).reverse().toString('hex') + '-' +
buffer.subarray(8, 10).toString('hex') + '-' +
buffer.subarray(10, 16).toString('hex');
}
Caution

The keyID derivation algorithms used by the endpoints /Harmonic and /Harmonic/v2 are different and will produce different values..