Skip to main content

SPEKE Key ID Extraction

Context​

SPEKE (Secure Packager and Encoder Key Exchange) is an open protocol defined by AWS that allows packagers to acquire encryption keys from a DRM key service. It is based on CPIX, which means, a caller would create an XML template describing all the necessary keys, and assigning a Key ID (GUID) to each key and submit this template to the key service. The key service inserts the generated keys into the same document and returns the augmented document back. The packager then uses the keys to encrypt the content.

Many packagers these days decide to use SPEKE for key acquisition.

Problem​

In an attempt to make the process as simple as possible for the users, some packagers treat the Key ID as an internal detail and do not expose it to the users. Users, however, need the value of the Key IDs so that later an entitlement can be granted for an end user to access a specific Key ID.

The Key ID can later be extracted from a generated manifest file, but this is sometimes inconvenient and can only be done after packaging is completed.

The problem is especially severe, as the AWS Elemental services including (MediaConvert and MediaPackage) do not expose the Key ID.

Alternative Solutions​

Instead of changing the Key ID in the Key Service, one could set up a proxy between the packager and the Key Service that would intercept the requests and store the Key ID before it is forwarded to the Key Service.

See SPEKE Key ID Extraction.

Solution: Proxy​

A possible solution is to use a Proxy between AWS Media Services and the Key Service.

AWS Media Services shall call the Proxy. The route for the request sent via Proxy is the following: AWS Media Services -> API Gateway -> Lambda -> Key Service. Additionally, the Proxy shall extract the resourceId and the keyId from the request and store them. The stored pairs of the resourceId and keyId can be used by the Entitlement Service or other components that need to know the binding between the resourceId and the keyId.

AWS packager -> API Gateway -> Lambda -> KS

Proxy between AWS Media Services and Key Service

The simplest way to run such a proxy is to use an AWS Lambda.

Here is a sample for such a proxy (simplified implementation):

Sample Proxy implementation using Python
import json
import requests
from xml.dom import minidom

def lambda_handler(event, context):
requestBody = event['body']

#Filter the values of resourceId and keyId
xmldoc = minidom.parseString(requestBody)

for element in xmldoc.getElementsByTagName('cpix:CPIX'):
resourceId = element.attributes['id'].value
print("Resource ID :", resourceId)

for element in xmldoc.getElementsByTagName('cpix:ContentKey'):
kid = element.attributes['kid'].value
print("keyId: ", kid)


#POST the request to SPEKE endpoint
spekeEndpoint = 'https://key-server-management.axprod.net/api/Speke'
authorizationHeader = "" # Basic base64("TenantID:ManagementKey")
headers = {
'Authorization': authorizationHeader,
'Content-Type': 'text/xml'
}

response = requests.request("POST", spekeEndpoint, headers=headers, data=requestBody)

#Pass through the response
return_value = {
"statusCode": response.status_code,
"headers": response.headers,
"body": response.text
}

return return_value

Such code can be deployed to AWS as a Lambda function. Then you can create an endpoint in an API Gateway pointing to this Lambda and supply this endpoint to Media Services and the endpoint for key acquisition.

The code assumes that the submitted request body contains a valid CPIX document. It extracts the resourceId (element cpix:CPIX, attribute id) and the keyId (element cpix:ContentKey, attribute kid). It prints both to the console. Then it simply forwards the same body to the real Key Service and passes the Key Service’s response to the caller.

For a real-life use, consider the following:

  • Instead of printing the resourceId and the keyId to the console, store them in some database (or deliver them in some other way to a location available for the Entitlement Service)
  • Instead of storing your Key Service credentials in the source code, use a more secure location, such as AWS Secret Manager
  • Add error handling
  • The code assumes there can be multiple resourceIds and keyIds. However, there will be only a single cpix:CPIX element, and SPEKE 1.0 only sends a single keyId.

Alternative Solution​

Instead of intercepting the Key ID generated by the package, one can instruct the Key Service to ignore the received Key ID and to generate a new Key ID according to a known published algorithm. Then users can compute the Key IDs themselves.

See SPEKE Key ID Override Functionality.

See also​