← Guides

KDM delivery

KDM basics for filmmakers: keys, validity windows, and why your DCP won't play

What a KDM is, how RSA-OAEP wrapped keys and the Recipient element work, and the validity-window mistakes that stop a DCP from playing.

You shipped an encrypted DCP to a festival. The projectionist ingests it, hits play, and gets a black screen or a blunt "key not valid" error. Nine times out of ten, nothing is wrong with the DCP — the problem is the KDM, a small XML file most filmmakers never look inside.

This post is the tour of that file: what it contains, how the cryptography actually works, and the four failure modes that account for nearly every "my DCP won't play" support call.

What a KDM is

KDM stands for Key Delivery Message, specified in SMPTE ST 430-1 (and typically wrapped in an ST 430-3 Extra-Theater Message envelope). It is a plain XML document whose entire job is to answer one question for one specific playback device: here are the content keys for this composition, and here is when you are allowed to use them.

Three facts frame everything else:

  1. The DCP and its keys travel separately. The package on the hard drive is ciphertext. The KDM arrives by email or a download portal, often days later.
  2. A KDM is addressed to one recipient. It is generated against the public certificate of a specific cinema server (or a specific mastering workstation). A KDM made for screen 3 cannot decrypt anything on screen 5.
  3. A KDM has a validity window. Outside that window, the keys are refused — by design, not by bug.

What is inside the file

Strip the XML scaffolding away and a KDM carries, per content key:

The wrapped key: RSA-OAEP and the 138-byte block

Each CipherValue is base64 text wrapping an RSA-OAEP encrypted block. OAEP (Optimal Asymmetric Encryption Padding) is the standard padding scheme that makes RSA encryption of small secrets safe; the practical consequence is that only the holder of the recipient's private key can unwrap it. The cinema server's private key never leaves the server; the KDM issuer only ever saw its public certificate.

Decrypt a CipherValue with the right private key and you get a fixed 138-byte block (ST 430-1 Table 6) containing, in order: a 16-byte structure ID (a fixed constant that identifies the block layout), the signer's thumbprint, the CPL id, a 4-character key type, the 16-byte KeyId of the encrypted asset, two 25-character validity timestamps, and finally the 16-byte content key itself.

The key type matters when a package has more than picture and sound: MDIK for picture, MDAK for audio, and MDEK for an encrypted Dolby ATMOS auxiliary data track. A KDM that only carries MDIK/MDAK will not unlock the ATMOS track of an encrypted Atmos package.

The Recipient element: how "addressed to you" is enforced

A recipient is identified not by a server name but by its certificate, named in KDMRequiredExtensions/Recipient as an X509IssuerSerial pair plus the full X509SubjectName — and that subject name carries a dnQualifier, which SMPTE ST 430-2 defines as base64(SHA-1(the DER of the RSA public key)). One key pair, one value. The real enforcement is arithmetic rather than a lookup: each content key is RSA-OAEP-wrapped to that certificate's public key, so a server without the matching private key cannot unwrap anything no matter what the XML claims. This is why regenerating a certificate, migrating a server, or swapping a certificate chain invalidates every KDM ever issued to the old identity.

A common confusion is worth heading off here. The AuthorizedDeviceInfo/DeviceList further down the file is not the addressing. That is the Trusted Device List — the equipment a rights owner permits to use the keys — and in the "Modified Transitional 1" formulation that essentially every tool ships today it contains a single fixed constant, 2jmj7l5rSw0yVb/vlWAYkK/YBwk=, the DCI "assume trust" thumbprint (base64 of SHA-1 over zero-length input). Reading the recipient out of it will tell you nothing.

The validity window

ContentKeysNotValidBefore and ContentKeysNotValidAfter are timestamps in the fixed 25-character form 2026-01-01T00:00:00+00:00 — UTC, seconds precision, numeric zone. (Distributors' tools sometimes emit Z or fractional seconds instead; a robust reader parses those leniently, but the numeric-UTC form is what the standard fixes and what the major packaging tools write.) The same window is duplicated inside each encrypted cipher block, so a projector can enforce it even after unwrapping.

The four failure modes

These are ordered by how often they actually cause a dark screen.

1. Expired KDM

The window closed. Festival KDMs are routinely issued for a few days around the screening; if the screening moves or the DCP is replayed a week later for a QA pass, the KDM has expired. The error a good player shows says exactly that — "content keys stopped being valid on…" — but a terse server may just say "key error". Check ContentKeysNotValidAfter first.

2. Not-yet-valid KDM, and the time zone trap

The mirror image: ContentKeysNotValidBefore is in the future. The classic variant is time zone confusion. The window is in UTC. A KDM issued with a window "from March 14" interpreted in local time can start hours after the first scheduled screening on the other side of the date line — or the festival's server clock is simply set to local time and misconfigured. When a not-yet-valid error appears on site, compare the server's UTC clock against the KDM window before assuming the distributor sent the wrong file.

3. Wrong recipient certificate

The KDM was generated against a different certificate than the one on the machine trying to use it. Causes, in rough order of frequency:

The diagnostic is mechanical: the dnQualifier inside the KDM's Recipient/X509SubjectName either equals your own certificate's dnQualifier or it does not. There is no "close enough". (Do not compare against the DeviceList — see above.)

4. Structural problems

Rarer, but real: a KDM whose cipher blocks reference a CPL id that does not match the KDM's own CompositionPlaylistId (a generator bug), a KDM with no EncryptedKey blocks at all, or a file that simply is not a KDM — a renamed XML, a truncated download. A quick structural sniff helps here: a genuine KDM contains a KDMRequiredExtensions element; if that string is absent, you are looking at something else (a key bundle JSON, a certificate, a CPL) regardless of the file extension.

What a careful player checks, in order

The sensible order of operations when ingesting a KDM is cheapest-check-first, decryption last, because "decryption failed" describes almost nothing:

  1. Is this a KDM at all? Look for KDMRequiredExtensions.
  2. Is it addressed to us? Compare the dnQualifier in Recipient/X509SubjectName against our own leaf certificate's. Mismatch → say so by name, with both identities in the message. Fall back to the DeviceList thumbprint only for legacy "Transitional 1" KDMs, which carried the recipient there and have no dnQualifier to read.
  3. Is the window live? Parse both validity dates (leniently — accept Z and fractional seconds) and compare against now. Not-yet-valid and expired deserve distinct, dated error messages, because they have different fixes.
  4. Only then, unwrap. RSA-OAEP-decrypt each CipherValue with the local leaf private key, verify the 138-byte structure ID, verify each block's embedded CPL id matches the KDM's CompositionPlaylistId, and extract KeyId + 16-byte key.

One deliberate omission: a playback tool ingesting a KDM it asked for is not a projector enforcing the DCI Compliance Test Plan, so it can reasonably skip ETM signature verification and signer-chain validation. The worst a forged KDM can do in that context is deliver keys that fail to decrypt the package — which surfaces as an ordinary key mismatch, not a security breach. A cinema server showing paying audiences has no such latitude.

A practical checklist for filmmakers


AlphaDCP ingests and verifies KDMs natively — recipient thumbprint match, validity-window check with dated errors, RSA-OAEP unwrap of each content key — and its sibling AlphaSUB uses the same parser when you open an encrypted DCP for subtitling, so a wrong-recipient or expired KDM is named as such instead of surfacing as an opaque decrypt failure. More at alpha-sub.com.