SKM REST API¶
The SKM API is an interface to a remote or local storage and management of cryptographic keys (media encryption keys for example). Each Key object has a unique key ID (KID) and a value (typically a 16-byte random number, like an AES-128 cipher key). Keys are stored encrypted with a KEK (Key Encryption Key) using a key wrapping algorithm (AES Key Wrap, RFC 3394). Each KEK has a corresponding KEKID (Key Encryption Key ID) which can be caller-assigned, or automatically computed by the server by deriving from the KEK value using a one way function. The server does not store the KEKs. Keys can be stored and retrieved in their encrypted form (in this case it is up to the caller of the API to perform the key wrapping and/or unwrapping), or they can be stored and retrieved in clear-text form by passing the KEK as an API parameter whenever needed (this this case, it is the server that performs the key wrapping and/or unwrapping).
Data Model¶
- A Key object has the following properties:
- KID (Unique)
- Key Value (byte array, encrypted with KEK). This value is not stored on the server
- EK (encrypted representation of the Value). This is stored on the server
- KEK_ID (String that identifies a KEK. May be derived from KEK through a one-way function)
- Info (arbitrary string)
- Content ID (arbitrary string used to remember the association of the key with a specific content/file)
- Expiration (if not null, the date/time at which the Key object expired; it may be removed automatically by the server)
- Last Update (date/time at which the Key object was last updated)
JSON representation
{
"kid": <hex> // (KID, 32 hex chars
"k": <hex> // Key Value (not stored in DB, dynamically computed from "ek")
"ek": <hex> // Key Value encrypted with KEK using AES Key Wrap
"kekId": <string> // KEK identifier
"info": <string> // (optional)
"contentId": <string> // (optional)
"expiration": <date> // (optional) expiration date of the object (ISO 8601 Extended Format)
"lastUpdate": <date> // (server-assigned) (ISO 8601 Extended Format)
}
Encrypted vs Clear-text Key Values¶
Keys are always stored on the server in their encrypted form. When Key values are exchanged through the API (either sent or received), they may be expressed either in their encrypted form (AES Key Wrap with a KEK), or in their raw clear-text form. If Key values are exchanged in their encrypted form, it is up to the caller to wrap or unwrap the key values with the appropriate KEK. If a kek
URL query parameter is present, the server will automatically perform the Key value wrapping or unwrapping.
REST API¶
Common API parameters¶
kek: | (optional). When specified, this parameter contains the 16-byte KEK used to unwrap the key value, in hexadecimal (32 hex characters) |
---|
Optional API parameters and extensions¶
Note
Some implementations of the SKM API require API callers to authenticate themselves. This may be implemented in a number of different ways, including using a URL query parameter (like for example an API key passed in a query parameter, named apiKey
, customerAuthenticator
, or something similar). URL query parameters must be separated with an &
character.
Special KID syntax¶
In order to facilitate the work of API clients, a 16-byte KID can be replaced by a ^
character followed by a string. In that case, the KID is simply computed as the 16-byte truncated SHA1 hash of the string.
For example, if the KID is specified as the string ^kid1
, the actual KID value is 80ea8bc8a58f990ad1f76bc665b30bfa
.
Root URL¶
Note
The URLs below are relative to a root URL for the Key Management Service on a server. In these examples, the root URL path is /
. But a server may use a different root URL path. For example, if the Key Management Service on a server named api.service.expressplay.com
is at a root URL path /keystore
, then the URL relative path keys/{kid}
would result in a final URL https://api.service.expressplay.com/keystore/keys/{kid}
if accessed with HTTPS.
API URLs¶
-
POST
/keys
¶ Create a new Key object
The
POST
body is either empty, in which case a brand new object, with a random KID, is created and returned (a KEK must be supplied through thekek
URL query parameter), or contain a JSON object with a partial or complete Key object.A partial Key object is one where not all fields are set. Fields that are not set are automatically generated by the server as follows:
- kid
- If the KID is not specified, a new random KID is chosen by the server. If the KID is specified, a new object is created with the specified KID, unless a Key object with the same KID already exists, in which case the rest of the POST body is ignored and the existing Key object is returned with an
HTTP 200
status code. - k
- If the clear-text Key Value is not specified, a new random key value will be chosen, using a cryptographically-strong random number generator.
- ek
- If the encrypted Key Value is not specified, a new random key value will be chosen, using a cryptographically-strong random number generator.
- kekId
- If a KEK ID is not specified, the server generates a KEKID value uniquely identifying the KEK
- info
- If the Key Info is not specified, this field remains empty
- contentId
- If the Content ID is not specified, this field remains empty
- expiration
- If no Expiration is specified, the expiration field is not set and the object does not expire.
The response contains a JSON object representing the Key object that was created or found.
Note
It is important to set the
Content-Type
HTTP header toapplication/json
when issuing aPOST
request with a JSON bodyExample Request: create a new random Key object
POST /keys?kek=000102030405060708090a0b0c0d0e0f HTTP/1.1
Response
HTTP/1.1 201 Created Content-Type: application/json Location: /keys/4e2df6b45e8257e187b2802b22ae7418 { "kid": "4e2df6b45e8257e187b2802b22ae7418", "k": "a9b9033df0b9ca5447839e3d074817a0", "ek": "5dbd06c0056b42fe0b8cf406679620c31bd619732730433d", "kekId": "#1.afe008a381bdac03b412a92d54b92ddf" }
Example Request: create a new Key object with all fields already set
POST /keys?kek=000102030405060708090a0b0c0d0e0f HTTP/1.1 { "kid": "4e2df6b45e8257e187b2802b22ae7418", "k": "a9b9033df0b9ca5447839e3d074817a0", "kekId": "my-kek-id-1", "contentId": "urn:mynamespace:my-content-id-1234", "info": "some comment" }
Response
HTTP/1.1 201 Created Content-Type: application/json Location: /keys/4e2df6b45e8257e187b2802b22ae7418 { "kid": "4e2df6b45e8257e187b2802b22ae7418", "k": "a9b9033df0b9ca5447839e3d074817a0", "ek": "5dbd06c0056b42fe0b8cf406679620c31bd619732730433d", "kekId": "my-kek-id-1", "contentId": "urn:mynamespace:my-content-id-1234", "info": "some comment" }
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Request JSON Object: - kid (string) – KID (32 hex characters)
- k (string) – Clear-text Key value (hex) [requires that the ‘kek’ query parameter be passed]
- ek (string) – Encrypted Key value (hex) [mutually exclusive with the presence of a ‘k’ field]
- kekId (string) – (optional) KEK Id
- info (string) – (optional) Key info
- contentId (string) – (optional) contentId
- expiration (string) – (optional) Object expiration data/time
Status Codes: - 200 OK – an existing Key object was found and returned
- 201 Created – a new Key object successfully created
-
PUT
/keys/{kid}
¶ Update a Key object
The
PUT
body must contain a JSON object for a partial or complete Key object. Fields that are not specified in the body will not be updated. Thekid
field, if present in the body, is ignored.Note
It is important to set the
Content-Type
HTTP header toapplication/json
when issuing aPUT
request with a JSON bodyExample Request: change the contentId of a Key object
PUT /keys/11a48707853ed5f13485f161523ffdc4 HTTP/1.1 { "contentId": "urn:namespace:x1234yyu" }
Response
HTTP/1.1 200 OK
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Request JSON Object: - k (string) – Clear-text Key value (hex) [requires that the ‘kek’ query parameter be passed]
- ek (string) – Encrypted Key value (hex) [mutually exclusive with the presence of a ‘k’ field]
- kekId (string) – (optional) KEK Id
- info (string) – (optional) Key info
- contentId (string) – (optional) contentId
- expiration (string) – (optional) Object expiration data/time
Status Codes: - 200 OK – no error
- 404 Not Found – key not found
-
GET
/keys/{kid}
¶ Returns one Key object
Example Request (without specifying the KEK)
GET /keys/11a48707853ed5f13485f161523ffdc4 HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: application/json { "kid": "11a48707853ed5f13485f161523ffdc4", "ek": "b6862c586af0d70fdc594deb7b254bb38937113dbc6411ea", "kekId": "#1.afe008a381bdac03b412a92d54b92ddf" }
Example Request (with KEK)
GET /keys/11a48707853ed5f13485f161523ffdc4?kek=000102030405060708090a0b0c0d0e0f HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: application/json { "kid": "11a48707853ed5f13485f161523ffdc4", "k": "d4783a651c96a872daa145ce1a378153", "kekId": "#1.afe008a381bdac03b412a92d54b92ddf" }
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Status Codes: - 200 OK – no error
- 400 Bad Request – bad request (ex: wrong KEK passed)
- 404 Not Found – key not found
-
GET
/keys/{kid}/value
¶ Returns one Key value
Instead of returning a complete JSON Key object, this request returns only the Key Value, as a hex string. If a KEK is passed in the kek query parameter, the response body contains the raw clear-text value of the Key object. If no KEK is passed, the response body contains the encrypted Key Value, prefixed with a
#
characterExample Request (with KEK)
GET /keys/00112233445566778899aabbccddeefc/value?kek=00112233445566778899aabbccddeeff HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: text/plain 12341234123412341234123412341234
Example Request (without KEK)
GET /keys/00112233445566778899aabbccddeefc/value HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: text/plain #ffaf1dae9201d1adf62770dca5ddb77ad773a79369e39986
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Status Codes: - 200 OK – no error
- 400 Bad Request – bad request (ex: wrong KEK passed)
- 404 Not Found – key not found
-
GET
/keys/{kid1},{kid2},...
¶ Returns mutliple Key objects
When multiple KIDs are specified, separated by ‘,’ characters, multiple Key objects can be retrieved with a single request. Just like for other requests, each KID may be expressed as a 32-character hex string, or a ‘^’ followed by an arbitrary string. The response body contains a JSON array of Key objects
Example Request
GET /keys/00112233445566778899aabbccddeefb,00112233445566778899aabbccddeefa,00112233445566778899aabbccddeeff/value?kek=000102030405060708090a0b0c0d0e0f HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: application/json [ { "kid": "00112233445566778899aabbccddeeff", "k": "ea85a33da18d55ffead60509a5666ad1" }, { "kid": "00112233445566778899aabbccddeefa", "k": "0ae81ee0bc16917f3758324c151f7010" }, { "kid": "00112233445566778899aabbccddeefb", "k": "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" } ]
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Status Codes: - 200 OK – no error
- 400 Bad Request – bad request (ex: wrong KEK passed)
- 404 Not Found – key not found
-
GET
/keys/{kid1},{kid2},.../value
¶ Returns multiple Key object values
This variant of the multiple-KID request returns the key values only instead of an array of JSON Key objects. As with the single-KID Key value request, the response body contains Key values either in raw clear-text form (when a KEK is passed), or in wrapped form (prefixed with
'#'
). The Key values in the response body are separated by','
charactersExample Request (with KEK)
GET /keys/00112233445566778899aabbccddeefb,00112233445566778899aabbccddeefa,00112233445566778899aabbccddeeff/value?kek=000102030405060708090a0b0c0d0e0f HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: text/plain a0a1a2a3a4a5a6a7a8a9aaabacadaeaf,0ae81ee0bc16917f3758324c151f7010,ea85a33da18d55ffead60509a5666ad1
Example Request (without KEK)
GET /keys/00112233445566778899aabbccddeefb,00112233445566778899aabbccddeefa,00112233445566778899aabbccddeeff/value HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: text/plain #7c98f3e4d60636d4aef4977d12dbfe75611dbd03e54dffef,#83017d13dc5067c1cff0ecab23184fd721832ad61f79ebfc,#81cf23495abdc2e6395a527c20a0bdc39e21549cfe0914f4
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Status Codes: - 200 OK – no error
- 400 Bad Request – bad request (ex: wrong KEK passed)
- 404 Not Found – key not found
-
DELETE
/keys/{kid}
¶ Delete a Key object
Example Request
DELETE /keys/00112233445566778899aabbccddeefb HTTP/1.1
Example Response
HTTP/1.1 200 OK
Status Codes: - 200 OK – no error
- 404 Not Found – key not found
-
GET
/keys
¶ Returns all the Key objects stored on the server
Example Request
GET /keys HTTP/1.1
Example Response
HTTP/1.1 200 OK Content-Type: application/json [ { "kid": "11a48707853ed5f13485f161523ffdc4", "ek": "b6862c586af0d70fdc594deb7b254bb38937113dbc6411ea", "kekId": "#1.afe008a381bdac03b412a92d54b92ddf" }, { "kid": "f0bacfca77d36361179b36a4cbee8abf", "ek": "a23ce0ab465f36a56f6e2863b16778cb7c7064662c1cbfa0", "kekId": "#1.afe008a381bdac03b412a92d54b92ddf", "info": "foobar" } ]
Query Parameters: - kek – (optional) KEK used to unwrap the key value
Status Codes: - 200 OK – no error