EZDRM

Using CPIX

The base CPIX request URL for EZDRM is the following:

https://cpix.ezdrm.com/keygenerator/cpix.aspx

To make a request query parameters are used to specify what is actually required. An example with parameters:

https://cpix.ezdrm.com/KeyGenerator/cpix.aspx?k=KeyID&u=USERNAME&p=PASSWORD&c=RESOURCENAME

The following is the CPIX document returned for the test URL above (query parameter values are defined in the next paragraph):

<cpix:CPIX id="1"
    xmlns:cpix="urn:dashif:org:cpix"
    xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc">
    <cpix:ContentKeyList>
        <cpix:ContentKey kid="77794df2-1783-4d59-bad7-80ea909a99b6"  explicitIV="d3lN8heDTVm614DqkJqZtg==">
            <cpix:Data>
                <pskc:Secret>
                    <pskc:PlainValue>7sigIvU2BT2kwdkspVcNrQ==</pskc:PlainValue>
                </pskc:Secret>
            </cpix:Data>
        </cpix:ContentKey>
    </cpix:ContentKeyList>
    <cpix:DRMSystemList>
        <cpix:DRMSystem kid="77794df2-1783-4d59-bad7-80ea909a99b6" systemId="edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
            <cpix:PSSH>AAAAdnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAFYIARIQd3lN8heDTVm614DqkJqZthoIbW92aWRvbmUiMnsia2lkIjoiZDNsTjhoZURUVm02MTREcWtKcVp0Zz09IiwidHJhY2tzIjpbIlNEIl19KgJTRA==</cpix:PSSH>
        </cpix:DRMSystem>
        <cpix:DRMSystem kid="77794df2-1783-4d59-bad7-80ea909a99b6" systemId="9a04f079-9840-4286-ab92-e65be0885f95">
            <cpix:PSSH>AAADBnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAubmAgAAAQABANwCPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgA4AGsAMQA1AGQANABNAFgAVwBVADIANgAxADQARABxAGsASgBxAFoAdABnAD0APQA8AC8ASwBJAEQAPgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAHAAbABhAHkAcgBlAGEAZAB5AC4AZQB6AGQAcgBtAC4AYwBvAG0ALwBjAGUAbgBjAHkALwBwAHIAZQBhAHUAdABoAC4AYQBzAHAAeAA/AHAAWAA9AEUAMAAxADgAMwBGADwALwBMAEEAXwBVAFIATAA+ADwARABTAF8ASQBEAD4AVgBsAFIANwBJAGQAcwBJAEoARQB1AFIAZAAwADYATABhAHEAcwAyAGoAdwA9AD0APAAvAEQAUwBfAEkARAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4AcwBXAGMARABtAEIASwAwAHoAdgBjAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</cpix:PSSH>
            <cpix:ContentProtectionData>PG1zcHI6cHJvIHhtbG5zOm1zcHI9InVybjptaWNyb3NvZnQ6cGxheXJlYWR5Ij41Z0lBQUFFQUFRRGNBandBVndCU0FFMEFTQUJGQUVFQVJBQkZBRklBSUFCNEFHMEFiQUJ1QUhNQVBRQWlBR2dBZEFCMEFIQUFPZ0F2QUM4QWN3QmpBR2dBWlFCdEFHRUFjd0F1QUcwQWFRQmpBSElBYndCekFHOEFaZ0IwQUM0QVl3QnZBRzBBTHdCRUFGSUFUUUF2QURJQU1BQXdBRGNBTHdBd0FETUFMd0JRQUd3QVlRQjVBRklBWlFCaEFHUUFlUUJJQUdVQVlRQmtBR1VBY2dBaUFDQUFkZ0JsQUhJQWN3QnBBRzhBYmdBOUFDSUFOQUF1QURBQUxnQXdBQzRBTUFBaUFENEFQQUJFQUVFQVZBQkJBRDRBUEFCUUFGSUFUd0JVQUVVQVF3QlVBRWtBVGdCR0FFOEFQZ0E4QUVzQVJRQlpBRXdBUlFCT0FENEFNUUEyQUR3QUx3QkxBRVVBV1FCTUFFVUFUZ0ErQUR3QVFRQk1BRWNBU1FCRUFENEFRUUJGQUZNQVF3QlVBRklBUEFBdkFFRUFUQUJIQUVrQVJBQStBRHdBTHdCUUFGSUFUd0JVQUVVQVF3QlVBRWtBVGdCR0FFOEFQZ0E4QUVzQVNRQkVBRDRBT0FCckFERUFOUUJrQURRQVRRQllBRmNBVlFBeUFEWUFNUUEwQUVRQWNRQnJBRW9BY1FCYUFIUUFad0E5QUQwQVBBQXZBRXNBU1FCRUFENEFQQUJNQUVFQVh3QlZBRklBVEFBK0FHZ0FkQUIwQUhBQWN3QTZBQzhBTHdCd0FHd0FZUUI1QUhJQVpRQmhBR1FBZVFBdUFHVUFlZ0JrQUhJQWJRQXVBR01BYndCdEFDOEFZd0JsQUc0QVl3QjVBQzhBY0FCeUFHVUFZUUIxQUhRQWFBQXVBR0VBY3dCd0FIZ0FQd0J3QUZnQVBRQkZBREFBTVFBNEFETUFSZ0E4QUM4QVRBQkJBRjhBVlFCU0FFd0FQZ0E4QUVRQVV3QmZBRWtBUkFBK0FGWUFiQUJTQURjQVNRQmtBSE1BU1FCS0FFVUFkUUJTQUdRQU1BQTJBRXdBWVFCeEFITUFNZ0JxQUhjQVBRQTlBRHdBTHdCRUFGTUFYd0JKQUVRQVBnQThBRU1BU0FCRkFFTUFTd0JUQUZVQVRRQStBSE1BVndCakFFUUFiUUJDQUVzQU1BQjZBSFlBWXdBOUFEd0FMd0JEQUVnQVJRQkRBRXNBVXdCVkFFMEFQZ0E4QUM4QVJBQkJBRlFBUVFBK0FEd0FMd0JYQUZJQVRRQklBRVVBUVFCRUFFVUFVZ0ErQUE9PTwvbXNwcjpwcm8+</cpix:ContentProtectionData>
        </cpix:DRMSystem>
        <cpix:DRMSystem kid="77794df2-1783-4d59-bad7-80ea909a99b6" systemId="94ce86fb-07ff-4f43-adb8-93d2fa968ca2">
            <cpix:URIExtXKey>c2tkOi8vZnBzLmV6ZHJtLmNvbS87Nzc3OTRkZjItMTc4My00ZDU5LWJhZDctODBlYTkwOWE5OWI2</cpix:URIExtXKey>
        </cpix:DRMSystem>
        <cpix:DRMSystem kid="77794df2-1783-4d59-bad7-80ea909a99b6" systemId="3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c">
            <cpix:PSSH>AAAAq3Bzc2gAAAAAPV5tNZuaQei4Q908bnLELAAAAIt7ImNvbnRlbnRJRCI6IlpETnNUamhvWlVSVVZtMDJNVFJFY1d0S2NWcDBaejA5IiwiZW5zY2hlbWEiOiJDRU5DIiwia2lkcyI6WyJOemMzT1RSa1pqSXhOemd6TkdRMU9XSmhaRGM0TUdWaE9UQTVZVGs1WWpZPSJdLCJ2ZXJzaW9uIjoiVjEuMCJ9</cpix:PSSH>
            <cpix:ContentProtectionData></cpix:ContentProtectionData>
        </cpix:DRMSystem>
    </cpix:DRMSystemList>
</cpix:CPIX>
~

The following query parameters can be used:

Parameter Description
k= Key ID value (client generated) in GUID format
u= Username
p= password
c= Content Resource ID (such as a stream name or media asset name)
'm' value not provided Default (returns all available keys)
m=1 MPEG_DASH (PlayReady and Widevine)
m=2 HLS (FairPlay)

For further details on the EZDRM CPIX API please consult the EZDRM documentation.

The resulting CPIX document then can be used as outlined in Content Protection Information eXchange (CPIX).

Adding WisePlay DRM

Support for WisePlay (by Huawei) is also achieved by calling the API for a CPIX document:

#!/bin/bash

curl -v https://eu-dev.ezdrm.com/keygenerator/cpix.aspx?k=77794df2-1783-4d59-bad7-80ea909a99b6&u=USERNAME&p=PASSWORD&c=1 > wiseplay.cpix

The returned document looks for instance like the following:

<?xml version='1.0' encoding='utf-8'?>
<CPIX xmlns="urn:dashif:org:cpix" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" xsi:schemaLocation="urn:dashif:org:cpix cpix.xsd">
  <ContentKeyList>
    <ContentKey kid="77794df2-1783-4d59-bad7-80ea909a99b6" commonEncryptionScheme="cenc">
      <Data>
        <pskc:Secret>
          <pskc:PlainValue>7sigIvU2BT2kwdkspVcNrQ==</pskc:PlainValue>
        </pskc:Secret>
      </Data>
    </ContentKey>
  </ContentKeyList>
  <DRMSystemList>
    <DRMSystem kid="77794df2-1783-4d59-bad7-80ea909a99b6" systemId="3d5e6d35-9b9a-41e8-b843-dd3c6e72c42c">
      <PSSH>AAAAq3Bzc2gAAAAAPV5tNZuaQei4Q908bnLELAAAAIt7ImNvbnRlbnRJRCI6IlpETnNUamhvWlVSVVZtMDJNVFJFY1d0S2NWcDBaejA5IiwiZW5zY2hlbWEiOiJDRU5DIiwia2lkcyI6WyJOemMzT1RSa1pqSXhOemd6TkdRMU9XSmhaRGM0TUdWaE9UQTVZVGs1WWpZPSJdLCJ2ZXJzaW9uIjoiVjEuMCJ9</PSSH>
      <ContentProtectionData />
    </DRMSystem>
  </DRMSystemList>
</CPIX>

Note

Please note that the systemId used is the same as 'ChinaDRM'.

The resulting CPIX document then can be used as outlined in Content Protection Information eXchange (CPIX), for instance:

#!/bin/bash

mp4split -o wiseplay.ism \
  --mpd.cpix=wiseplay.cpix \
  test.mp4

Attention

WisePlay is only available for MPEG-DASH.

Note

The following section outlines the pre-CPIX APIs.

Adding FairPlay DRM

Using EZDRM's web service, the bash script below retrieves the Adding FairPlay DRM values from the web service and then adds it to the mp4split command to create a server manifest.

The U and P values should be replaced with your credentials (username and password).

#!/bin/bash

resp=`curl -X POST -v 'http://fps.ezdrm.com/api/keys?U=USERNAME&P=PASSWORD' -d ''`

cek16=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//KeyHEX").text'`

mp4split -o fairplay.ism \
  --hls.key=:${cek16:0:32} \
  --hls.key_iv=${cek16:32:32} \
  --hls.playout=sample_aes_streamingkeydelivery
  test.mp4

Please note how the KeyHEX value is split into content key (the first 16 bytes) and key_iv (the second 16 bytes): the key_iv is not listed in the playlist but it is a value shared between encryption and playout. The player will receive it as part of the key request.

Adding PlayReady (CENC)

Using EZDRM's web service, the bash script below retrieves the Widevine specific data from the web service and then adds it to the mp4split command to create a server manifest.

The U and P values should be replaced with your credentials (username and password).

#!/bin/bash

resp=`curl -s 'http://wvm.ezdrm.com/ws/LicenseInfo.asmx/GenerateKeys?U=USERNAME&P=PASSWORD&C=""'`

cek=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/KeyHEX").text'`
kid=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/KeyIDHEX").text'`
laurl=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/LAURL").text'`

mp4split -o playready.ism \
  --iss.key=${kid}:${cek} \
  --iss.license_server_url=${laurl} \
  test.mp4

Adding PlayReady (PIFF)

Using EZDRM's web service, the bash script below retrieves the PlayReady specific data from the web service and then adds it to the mp4split command to create a server manifest.

Please note this for HSS/PIFF, not DASH/CENC - see below for multi DRM CENC.

The U and P values should be replaced with your credentials (username and password).

#!/bin/bash

resp=`curl -s 'http://wvm.ezdrm.com/ws/LicenseInfo.asmx/GenerateKeys?U=USERNAME&P=PASSWORD&C=""'`

cek16=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/KeyHEX").text'`
kid=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/KeyIDGUID").text'`
laurl=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/LAURL").text'`

# Service returns as GUID so convert to UUID
kid16=`python -c "exec(\"import uuid,base64; print base64.b16encode(uuid.UUID(base64.b16encode(uuid.UUID('$kid').bytes_le)).bytes);\")";`

mp4split -o playready.ism \
  --iss.key=${kid16}:${cek16} \
  --iss.license_server_url=${laurl} \
  test.mp4

Adding Widevine (CENC)

Using EZDRM's web service, the bash script below retrieves the Widevine specific data from the web service and then adds it to the mp4split command to create a server manifest.

The U and P values should be replaced with your credentials (username and password).

#!/bin/bash

resp=`curl -s 'http://wvm.ezdrm.com/ws/LicenseInfo.asmx/GenerateKeys?U=USERNAME&P=PASSWORD&C=""'`

cek=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/KeyHEX").text'`
kid=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/KeyIDHEX").text'`
pssh=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/PSSH").text'`
laurl=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/ServerURL").text'`

mp4split -o widevine.ism \
  --widevine.key=${kid}:${cek} \
  --widevine.drm_specific_data=${pssh} \
  test.mp4

Using CENC multi DRM

The combination of PlayReady and Widevine as CENC multi DRM is supported as well, in this setup a single key id and content key combination is valid for both PlayReady and Widevine: Common Encryption.

The U and P values should be replaced with your credentials (username and password).

To use this you would need to combine the CENC options as described above, e.g.

#!/bin/bash

resp=`curl -s 'http://wvm.ezdrm.com/ws/LicenseInfo.asmx/GenerateKeys?U=USERNAME&P=PASSWORD&C=""'`

cek=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/KeyHEX").text'`
kid=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/KeyIDHEX").text'`
laurl=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//PlayReady/LAURL").text'`
pssh=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/PSSH").text'`
serverurl=`echo $resp | python -c 'import sys, xml.etree.cElementTree as et; tree = et.parse(sys.stdin); print tree.find(".//WideVine/ServerURL").text'`

mp4split -o playready.ism \
  --iss.key=${kid}:${cek} \
  --iss.license_server_url=${laurl} \
  --widevine.key=${kid}:${cek} \
  --widevine.drm_specific_data=${pssh} \
  test.mp4