How it is built
Architecture overview
A DRM system lets a service distribute encrypted video to the public and still decide, per viewer and per device, who may decrypt it. The media is encrypted once at packaging time and served from an ordinary CDN to everyone. The content key never travels with it. A player that wants to play asks a license server for the key, proves who it is and what device it runs on, and receives the key wrapped for one specific decryption module on that device. The decryption module (the content decryption module, CDM) holds the key where the application cannot read it and decrypts samples on request.
The idea that makes it work is separating the cheap, public part from the small, guarded part. Bulk bytes (the media) are public, cacheable, identical for all viewers. The only secret-bearing traffic is the license exchange: a few kilobytes per playback start, which a service can protect carefully (attestation of the device, signed requests, short-lived tokens, rate limits, per-user policy) without the cost showing up in bandwidth. The business rules (which title, which resolution, how long, how many devices) live in the license server's policy, and the device-side module enforces them.
Parts:
- Packager — encrypts the media with content keys and writes the key id into the file — Common Encryption (CENC), AEAD (AES-GCM, ChaCha20-Poly1305), csprng (no page yet)
- Key management — creates, stores, rotates and wraps content keys — Envelope encryption, aes-key-wrap (no page yet), HKDF key derivation (extract-and-expand), Secrets management
- License server — checks the request, applies policy, returns the wrapped key — JSON Web Token (JWT), OAuth 2 and OpenID Connect, Sessions vs tokens, Digital signatures (Ed25519), Message authentication codes (HMAC, CMAC, Poly1305, KMAC), Mutual TLS, constant-time-code (no page yet),
hdr-histogram(no page yet) - Device trust — proves the requester is a real, unmodified device with a protected module — remote-attestation (no page yet), trusted-execution-environments (no page yet), measured-boot (no page yet), Secure boot chain, hardware-backed-keystore (no page yet), x509-certificates (no page yet)
- Abuse control — limits request rates and bursts per account and device — Token bucket
- Store and availability — key and entitlement data that must not be lost, served from more than one place — Primary-backup replication, Write-ahead log, Point-in-time recovery, Object storage, Leases, Fencing tokens, Health checking, Graceful draining, Process supervision
- Assurance — the testing that finds the bugs a licence service cannot afford — Coverage-guided fuzzing, Deterministic simulation testing, Code coverage instrumentation
PACKAGING (once per title) PLAYBACK (per viewer)
source ─► encoder ─► packager ──► CDN ──► player (browser / app / TV)
│ (CENC, key id) ▲ │ 1. read key id + init data from file
│ │ ▼
│ encrypted CDM ◄─┐ (hardware-backed where available)
▼ segments │ │ 4. wrapped key
key service │ 2. license request (signed, device cert)
(envelope-encrypted keys) ▼ │
▲ ┌── license server ──┐
└─── content key ◄──────┤ auth + entitlement │── store (replicated, WAL, backups)
│ attestation check │
└── rate limit, log ──┘
3. app proof of entitlement (token) goes along the request
The same design appears under different brand names: Widevine, FairPlay Streaming and PlayReady are three such systems, each with its own license protocol and device module, which is why one encrypted file must work for several of them (see Common Encryption below).
How the parts fit together
Packager
The packager encrypts every media sample with AES under a content key named by a 16-byte key id, leaves the bytes a player must parse in the clear, and writes the key id and system-specific init data (pssh boxes) into the file. This is Common Encryption (CENC), defined by ISO/IEC 23001-7: the file is encrypted once and any DRM system that understands the scheme can obtain the key through its own license exchange. The schemes are cenc (AES-CTR), cbc1, cens and cbcs (the last two use a block pattern; cbcs is what HLS fragmented MP4 uses per RFC 8216). Why this block and not a custom envelope: a service wants one set of encrypted segments on the CDN for all platforms, not one copy per DRM vendor. The encryption of samples is a stream-cipher or CBC pass, not AEAD (AES-GCM, ChaCha20-Poly1305): media segments have no room for per-sample authentication tags and are checked by container structure; AEAD belongs to the license exchange and key storage instead. Content keys come from a csprng (no page yet), the operating system's secure random source.
Key management
Content keys are the crown jewels of the service, and there can be millions of them. Envelope encryption is the storage pattern: each content key is encrypted under a key-encryption key held in a key management service or hardware module, so the database holds only wrapped keys and rotating the key-encryption key means re-wrapping, not re-encrypting media. Deterministic key wrapping (aes-key-wrap, no page yet; RFC 3394 and RFC 5649) is the standard way to wrap a small key under another key. HKDF key derivation (extract-and-expand) derives per-session or per-purpose keys from a master secret so that the same master never directly protects two things. Secrets management governs how the service itself reaches the key-encryption key: short-lived identity, no keys in images or logs, routine rotation. The contract with the license server is narrow: a call that takes a key id and returns the content key, available only to authenticated license-server instances.
License server
The license server receives a request from the CDM, validates it, decides whether this user may watch this title on this device now, and answers with the content key wrapped to the device's module. Its authentication has two layers. The device layer (below) proves the module is genuine. The user layer proves entitlement: the app calls its own backend, which authenticates the user with OAuth 2 and OpenID Connect or a session (Sessions vs tokens), and passes the license server a signed claim in the request. A JSON Web Token (JWT) is a common form of that claim; the verifier must pin the algorithm, check expiry, audience and issuer, and look up the key by id. Signatures use Digital signatures (Ed25519) or an RSA or ECDSA alternative, and shorter integrity checks use Message authentication codes (HMAC, CMAC, Poly1305, KMAC). Between the backend and the license server, Mutual TLS gives each service a verified identity. The comparison of secrets and tags goes through constant-time-code (no page yet) routines, so response time does not leak how many bytes matched.
Playback cannot start until the licence answer arrives, so the licence round trip is the latency users feel. hdr-histogram (no page yet) records the time of each licence request, split into device check, entitlement lookup and key unwrap, as percentiles. The budget is set on the slow tail, because a few seconds of delay at start is what drives people to abandon a stream, and the same numbers show whether a rate limit or a store failover has begun to hurt.
Device trust
Without device trust, the key would simply be handed to any program that asks. The license server therefore needs evidence that the requester is a module it recognizes. Three blocks stack: Secure boot chain (each stage verifies the next, anchored in an immutable root), measured-boot (no page yet) (each stage's hash is recorded in a TPM-style register), and remote-attestation (no page yet) (hardware-signed evidence of that state, checked by the server against a certificate chain, x509-certificates, no page yet). Device keys live in hardware-backed-keystore (no page yet) storage, or in a trusted-execution-environments (no page yet) enclave where the CDM runs. The license server's policy can then tie output quality to trust: a verified hardware path may receive high-resolution keys, a software-only module only lower resolution. This is the reason the policy engine and the attestation check are in the same service. Which levels and how many exist is vendor-specific; each system's documentation describes its own. For example, Widevine's public page says its licenses are issued through a Cloud License Service or a License Server SDK, with requests processed via a proxy.
Abuse control
License requests come from a closed set of clients, which makes abuse patterns visible: account sharing, key scraping from a patched player, request floods. A Token bucket per account and per device bounds the average request rate while allowing the burst that a seek or a channel change causes. The limit is a control, not a security boundary; the real protection is that the key is useless outside an attested module. The alternative algorithms (GCRA, sliding-window counters) differ in memory and smoothness, not in purpose.
Store and availability
A license server has to be up whenever any viewer presses play, and it must never lose a key or an entitlement. The state is small and write-light: content keys, device registrations, entitlement and revocation lists, audit records. A single primary with synchronous replication to a standby fits: Primary-backup replication, with the acknowledgement rule decided by how much loss is acceptable and an external arbiter or Leases with Fencing tokens deciding who is primary, so a paused old primary cannot write after takeover. Each node's store uses a Write-ahead log for durability; Point-in-time recovery with base backups in Object storage covers operator mistakes and corruption, which replication copies faithfully. Health checking removes bad instances from rotation, Graceful draining lets in-flight license requests finish at deploy time, and Process supervision restarts a crashed process. The classic recovery algorithm (ARIES recovery) and the Buffer pool matter only if the store is a self-built database; with an off-the-shelf database they are the database's concern.
Assurance
A license service parses attacker-controlled messages (the request from the device) and handles keys, so the cost of one bug is large. Coverage-guided fuzzing of the request parser, with Code coverage instrumentation as its feedback, finds crashes and mis-parses before attackers do. Deterministic simulation testing runs the replication and failover logic under a seeded scheduler with simulated network faults, so a rare split-brain bug replays exactly. fault-injection (no page yet), delta-debugging (no page yet) and sanitizers (no page yet) support those two.
Data and control flow
Flow 1: packaging a title
- The packager reads the encoded streams and asks the key service for a content key and key id for each track (often separate keys for audio, SD, HD and UHD video).
- It encrypts every sample under the track's key with the chosen scheme (
cencorcbcs) and writes the key id, scheme, per-sample IVs and clear/protected ranges into the file. - It adds one
psshbox per DRM system the service supports, then uploads the segments and manifest to object storage and the CDN. - The key service stores the content key envelope-encrypted and registers the title's key ids with the license server's entitlement rules.
Flow 2: starting playback
- The player downloads the manifest and the first segment; the file's init data names the key id.
- In a browser, the page calls the Encrypted Media Extensions API:
requestMediaKeySystemAccessselects a key system and its capabilities,createMediaKeyscreates the key object, andgenerateRequeston a session passes the init data to the CDM (W3C EME). - The CDM produces a license request and signals it to the page as a
messageevent. The page sends it, with the user's entitlement token, to the license server over TLS. - The server verifies the token and the device evidence, checks policy and rate limits, loads the wrapped content key, wraps it for this device and returns the license.
- The page passes the response to the session's
updatecall. The CDM stores the key in its protected area and reports key status through akeystatuseschangeevent. - The player feeds encrypted samples to the CDM, which decrypts them into a protected path or returns them to the decoder. Time to first frame includes this round trip, so the license server must answer in tens of milliseconds, not seconds (order of).
Flow 3: revocation and rotation
- A device model is found compromised, or a user stops paying. The service adds the device or user to the revocation or entitlement store.
- New license requests from those devices are refused. Licenses already issued stay valid until they expire, so license duration is the lever: short for live and rentals, longer for offline downloads.
- For live streams, content keys rotate during the stream; the player asks for new licenses ahead of time, which is why the license server's availability, not its bandwidth, is the critical path.
Scaling
The license endpoint is small and read-mostly, so it scales horizontally, with the following limits in the order they appear. First are TLS handshakes and signature verifications per second at a peak, such as a popular live event starting; keep sessions alive, use fast signatures, and spread load across regions. Second is the key store read path: cache unwrapped keys in memory only for as long as the policy allows, or cache the wrapped form and unwrap through the key service. Third is the key management service, which is often rate-limited by its provider; batch unwraps and cache. Fourth is the primary for writes: writes are rare (registrations, revocations), so a single primary suffices; read replicas serve license reads. Fifth is regional availability: place replicas near users, but keep a single write authority to avoid divergent entitlements. Last is abuse load, which a Token bucket and early rejection of unauthenticated requests absorb before the expensive parts.
Failure modes
| Failure | Symptom | Cause | Fix |
|---|---|---|---|
| Playback never starts | Spinner after press, license request fails | License server down, token expired, clock skew | Multi-region servers, clock sync, retry with backoff, clear client error |
| Black screen with audio | Audio plays, video does not | Device refused the HD key because its trust level is too low | Policy fallback to a lower resolution track |
| Wrong key | Garbled picture or decrypt error | Key id mismatch between packager and key service, or wrong scheme | Verify key id and scheme at packaging; tests on every target device |
| One platform fails | Works in browser, fails on a TV | Missing pssh for that system, or cenc against a device that only supports cbcs | Package for both schemes or standardize on one, test the matrix |
| License storm | Latency spike when a live event starts | Everyone requests at once; no rate limiting | Spread license fetch with jitter, pre-fetch, scale out |
| Stale revocation | A banned device still plays | Long-lived licenses, caches not invalidated | Shorter license duration, push revocations to caches |
| Key leak | Content appears on pirate sites | Key extracted from a weak (software-only) module | Lower-tier devices get lower resolutions; revoke the device model |
| Split brain | Two primaries accept writes | Failover without fencing | Leases with fencing tokens; arbiter outside the pair |
| Parser crash | License server dies on a crafted request | Memory-safety bug in parsing | Fuzz the parser, use a memory-safe language, isolate the process |
Real implementations
| name | what it is | repo | licence | notes |
|---|---|---|---|---|
| Shaka Packager | media packager with DASH, HLS and encryption | shaka-project/shaka-packager | BSD-3-Clause | CENC packaging; README lists DASH and HLS packaging and encryption |
| Shaka Player | JavaScript player with EME support | shaka-project/shaka-player | Apache-2.0 | DRM playback in browsers |
| dash.js | DASH reference player | Dash-Industry-Forum/dash.js | BSD-3-Clause | MPEG-DASH playback in browsers |
| Media3 / ExoPlayer | Android media library | androidx/media | Apache-2.0 | Android media library; the Widevine page names ExoPlayer for Android playback |
| Widevine | Google's DRM system | developers.google.com/widevine | proprietary | documents the Cloud License Service and License Server SDK |
| FairPlay Streaming | Apple's DRM system | developer.apple.com/streaming/fps | proprietary | for HLS on Apple platforms |
| PlayReady | Microsoft's DRM system | learn.microsoft.com/playready | proprietary | official documentation |
No complete open-source production license server is listed, because none was verified for this page. Streaming services that use these systems include Netflix, Disney and Warner Bros. Discovery; their internal designs are not public.
Sources
- W3C, Encrypted Media Extensions. spec
- W3C, Encrypted Media Extensions: Initialization Data Format Registry,
cencformat. spec - ISO/IEC 23001-7, Common encryption in ISO base media file format files (standard; cited by number).
- RFC 8216, HTTP Live Streaming. rfc
- RFC 3394, Advanced Encryption Standard (AES) Key Wrap Algorithm; RFC 5649, AES Key Wrap with Padding Algorithm (RFC 3394: rfc; RFC 5649: rfc).
- Widevine DRM overview. docs
- Apple, FairPlay Streaming. docs
- Microsoft, PlayReady. docs
- DASH Industry Forum guidelines. docs