Why This Matters

If you ship paid video on the open internet, you encrypt with CENC. There is no other way to put Widevine, FairPlay, and PlayReady on the same encoded segments, and shipping all three is the price of reaching every household device — see our DRM 101 article for why one DRM is never enough. For a product manager scoping an OTT launch this article is the answer to "why do we encrypt once but pay for three DRMs?". For an engineer it is the field guide to the pssh box, the tenc box, the default_KID, and the difference between cenc and cbcs that turns a working CMAF pipeline into a broken FairPlay one. For a founder weighing the storage cost of dual-encryption vs single-encryption it is the cost ladder that the DASH-IF Implementation Guidelines for Security tipped permanently toward cbcs after September 2020.

What Common Encryption Actually Is

Before any acronym lands, let's pin down the job. The packager that prepares a video for streaming has to make the file unplayable to anyone without permission. It does that by encrypting the audio and video samples — the actual pixels and audio waveforms — inside the file's container, using a symmetric key called the content key that only authorised players can fetch. Common Encryption is not the encryption itself; it is the agreed format for how that encryption is written into the file so that any compliant DRM can recognise the file and ask for the right key.

In other words, CENC answers four questions that every multi-DRM stream has to answer:

  1. Which bytes inside each video sample are encrypted, and which stay in the clear? — so the player's media platform can still parse the container and the codec's structural bits without holding the key.
  2. Which key was used? — by recording a 16-byte identifier called the default_KID in a metadata box.
  3. Which DRM systems are allowed to unlock this file, and how does each one find its license server? — by writing one or more pssh boxes, one per DRM.
  4. What encryption mode and pattern are in force? — by writing a four-letter scheme tag (cenc, cbc1, cens, or cbcs) into a schm box.

Pin those four questions in your head and the rest of the article is just filling in the details. The standard that defines all four is ISO/IEC 23001-7:2023 — currently in its 3rd edition, published in late 2023, layered on top of the ISO Base Media File Format (ISO/IEC 14496-12) that defines MP4, fragmented MP4, and CMAF containers.

The standard does not define a key-management protocol, a license-server API, or a particular DRM. It is deliberately neutral: any DRM that can read the file's metadata and acquire the right content key can decrypt the content. That neutrality is the whole point — one encryption, many DRMs.

A single CMAF segment encrypted once with cbcs and decryptable by Widevine, FairPlay, and PlayReady through three PSSH boxes Figure 1. One file, four metadata boxes, three DRMs. The CENC architecture in a single picture.

The Four Protection Schemes (And Why Two Survive)

The standard defines four schemes, and the names matter because they appear in your packager flags, your manifest signalling, and your debug logs. Each scheme picks two choices: block-cipher mode (counter mode CTR vs cipher-block-chaining CBC) and encryption coverage (every byte of the sample vs a periodic pattern).

cenc — AES-128 in CTR (counter) mode, applied to the entire content of each subsample. This was the original 2012 scheme and the historical default for MPEG-DASH on non-Apple devices. CTR mode lets the decoder seek and decrypt samples in parallel without needing the previous sample's ciphertext, which made it the natural fit for fast video pipelines.

cbc1 — AES-128 in CBC mode, applied to the entire content of each subsample. Defined but almost never deployed. CBC mode chains each 16-byte block to the previous one, which makes random access slightly more expensive than CTR.

cens — AES-128 in CTR mode with a pattern: only one of every ten 16-byte blocks inside a subsample is encrypted; the other nine are left in the clear. The pattern was added so that older smart TV chips and low-end phones could decrypt high-bitrate streams in real time without the CPU melting. Defined but rare in production.

cbcs — AES-128 in CBC mode with the same one-of-ten pattern. This is the scheme Apple FairPlay Streaming requires, and the scheme that became the production default in 2026. The pattern is technically crypt_byte_block = 1 and skip_byte_block = 9 — encrypt one 16-byte block, skip nine, repeat — measured per NAL-structured video subsample.

Of those four, only two ship in production: cenc (legacy DASH, pre-2018) and cbcs (Apple-compatible, everyone-compatible, 2026 default). The pattern modes cens and cbc1 exist on paper, but no major DRM ecosystem has standardised on them.

Why the pattern matters at all is worth a paragraph. A 4K HDR stream at 30 frames per second pushes roughly 15 to 25 megabits per second of encoded video. If every byte of every video sample had to pass through an AES round on a five-year-old smart TV, the chip's hardware accelerator could fall behind real time. The pattern encryption was introduced by Apple in 2014 (in the original FairPlay Streaming for HLS) specifically because the iPhone 4s and earlier devices couldn't afford to AES-decrypt every byte of HD video in software. Encrypting one block in ten gives roughly the same security against a passive attacker — the encrypted blocks are scattered enough that the clear blocks reveal no useful structure to a codec parser — at one-tenth the CPU cost. Once Apple shipped cbcs as the FairPlay default, the rest of the industry had to follow.

The remarkable fact about 2026 is how completely cbcs won. Apple required it on day one (FairPlay has never supported anything else). Widevine added full cbcs support in mid-2018 with Modular DRM v15. PlayReady added cbcs support in v4.2 (2019). The DASH-IF Content Protection Information Exchange (CPIX) and DASH-IF Implementation Guidelines for Security cemented the convention: encrypted DASH content SHALL use either the cenc or the cbcs protection scheme, the two are mutually exclusive within an adaptation set, and modern packagers default to cbcs because it is the only one Apple will decrypt.

A side-by-side byte-level diagram showing cenc full-subsample CTR encryption versus cbcs pattern CBC encryption with the 1-encrypted-9-clear pattern Figure 2. Byte-level view: cenc encrypts every block of every subsample; cbcs encrypts one block in ten over the same range.

The Metadata Boxes That Hold It All Together

ISO/IEC 23001-7 defines a small set of metadata boxes — short, self-describing binary blocks — that the packager writes into every protected file. There are four you must know.

schm (Scheme Type box) sits inside the file's sample-description hierarchy and carries the four-letter scheme name. When you read a CMAF init segment with mp4dump or Bento4, you will see schm reporting cenc or cbcs somewhere under moov/trak/mdia/minf/stbl/stsd/sinf/schm. The single four-letter code is what tells the player which decryption mode to use.

tenc (Track Encryption box) is the most important box in the file. It carries the default encryption parameters for every sample in the track: the default_KID (the 16-byte key identifier that says which content key was used), the default IV size, the default crypt-byte-block and skip-byte-block for pattern schemes, and the default "is protected" flag. Per DASH-IF guidance, every protected track has exactly one tenc box, found at moov/trak/mdia/minf/stbl/stsd/sinf/schi/tenc. The default_KID from tenc is the value the manifest copies into its cenc:default_KID attribute, and the value the player passes to the DRM as "I need the key with this ID".

The default_KID is a 128-bit value, written in string form as a 32-hex-digit identifier with hyphens — for example 34e5db32-8625-47cd-ba06-68fca0655a72. Visually it looks like a UUID, but the standard does not constrain the bit pattern the way RFC 4122 does, so don't validate it as a UUID — validate it as an arbitrary 16-byte identifier. A common bug is that some Windows libraries serialise the first three groups in little-endian byte order (the "Microsoft GUID" convention) while every other tool serialises in big-endian. The DASH-IF guidelines state explicitly that the byte order SHALL be identical in the binary tenc box and the string-form attribute in the MPD. Get that wrong and license requests succeed with the wrong key, and playback fails silently.

pssh (Protection System Specific Header box) is where multi-DRM happens. One pssh box per DRM system, each carrying a 16-byte System ID that identifies the DRM vendor, plus a small DRM-specific payload (Widevine puts a Protobuf message; PlayReady puts a base-64 XML "Pro header"; FairPlay typically omits the box and uses HLS-native EXT-X-KEY lines instead). The System IDs are not invented per stream — they are issued centrally and maintained on the DASH-IF DRM-system identifier registry. The three you will see in every multi-DRM stream are:

  • Widevineedef8ba9-79d6-4ace-a3c8-27dcd51d21ed
  • PlayReady9a04f079-9840-4286-ab92-e65be0885f95
  • Apple FairPlay94ce86fb-07ff-4f43-adb8-93d2fa968ca2 (rarely written into the file; FairPlay licensing is normally signalled in the HLS manifest, not in a moov/pssh box)
  • W3C Common SystemID1077efec-c0b2-4d02-ace3-3c1e52e2fb4b (defined by the W3C "cenc" Initialization Data Format so a player can ask for keys by KID without picking a specific DRM vendor)

DASH-IF's modern guidance is to place pssh boxes in the MPD manifest rather than in the moov of the init segment, because manifests are easier to update than re-muxing rewritten init segments every time you add a DRM. The init segment can ship without a moov/pssh at all, and the player picks up the pssh data from the manifest's element under cenc:pssh (base64-encoded). HLS does the same job through the EXT-X-KEY and EXT-X-SESSION-KEY tags.

senc, saiz, saio (per-sample encryption metadata) sit inside each fragment's moof/traf and carry the per-sample initialisation vectors and, if subsample ranges vary, the subsample byte counts. You will not normally touch these by hand; the packager writes them. But if mediastreamvalidator or Bento4's mp4dump complains about a missing senc box, you know which layer broke.

Anatomy of a CMAF initialization segment showing the moov hierarchy with schm, tenc, and pssh boxes located inside their parent boxes Figure 3. Where each CENC box lives inside a CMAF initialization segment.

How One Encryption Becomes Three Licenses

The trick that makes multi-DRM economical is not in the cryptography — it is in the addressing. Here is the chain end to end, walked once so the rest of the section is shorthand.

The packager encrypts each adaptation set with a single 16-byte content key — call it K. It records the key's 16-byte identifier — the default_KID — in the tenc box, and writes one pssh box per DRM system it plans to support. Each pssh box names the DRM through its System ID and carries a small DRM-specific payload that lets the DRM's license server recognise this exact stream.

The packager does not store K anywhere in the file. K lives only in the streaming service's Key Management System (KMS), keyed by default_KID. The encrypted file is useless without K, and K is only ever released to a DRM's license server, never to the player directly.

When a viewer hits play, the player loads the manifest, sees the protection signalling, and selects a DRM that the device supports (Widevine on Chrome, FairPlay on Safari, PlayReady on a Tizen TV). The player passes the matching pssh data — or in HLS, the EXT-X-KEY data — to the device's Content Decryption Module via the W3C Encrypted Media Extensions API. The CDM produces a license-request blob, the player POSTs it to the streaming service's license-server endpoint, the license server authenticates the request, fetches K from the KMS keyed by default_KID, wraps K in a DRM-specific license blob, and returns it. The CDM unwraps K inside its protected memory, decrypts each sample using the IV from the senc box and the encryption mode declared in schm, and the decoded pixels go straight to the device's hardware video pipeline — never visible to JavaScript, the kernel, or any unprivileged process.

That is the whole multi-DRM trick. One file, one key, multiple DRMs, each with its own license server, each agreeing on the same default_KID as the lookup index. The differences between the three DRMs are entirely below the API surface — they all speak through EME to the same CENC-encrypted bytes.

The 2026 Default: CMAF + cbcs + Dual-Manifest

Read this section as the practical takeaway from everything above.

In 2026 the dominant pattern across paid streaming services is what we will call the single-encryption multi-DRM stack: one set of CMAF-packaged fMP4 segments, encrypted once with the cbcs scheme, signalled in two manifests — an HLS playlist for Apple devices and an MPEG-DASH MPD for everywhere else — and decrypted by Widevine, FairPlay, or PlayReady depending on which CDM the device ships. The same segment files serve all three DRMs.

This was not always the default. From 2012 through roughly 2018 the industry ran a dual-encryption stack: encode the catalogue, then encrypt it twice — once with cenc for the DASH/Widevine/PlayReady path, and once with cbcs for the HLS/FairPlay path — store both copies on the origin, and serve them through two separate manifest pipelines. The cost was a clean doubling of origin storage for every encrypted asset, plus the operational overhead of keeping two parallel package pipelines synchronised.

The shift to cbcs-only happened in three steps. First, Apple's release of fMP4-in-HLS support in WWDC 2016 made it technically possible to use the same CMAF segments for both protocols. Second, the DASH-IF Implementation Guidelines for Security formalised the convention that cbcs is a permitted DASH protection scheme — historically DASH had defaulted to cenc. Third, the major DRM vendors added full cbcs support to their license servers and CDMs (Widevine in 2018, PlayReady in 2019), removing the last reason to maintain a parallel cenc pipeline.

By 2026 the storage savings are dispositive. A streaming service shipping a thousand hours of catalogue at 4K HDR + 1080p SDR + audio renditions stores roughly 8 TB per encoding pass; the dual-encryption path doubled that to 16 TB. The dual-encryption path also doubled bandwidth on package republish, multiplied the cache footprint at every CDN edge, and forced two key-management pipelines through the KMS. Single-encryption cbcs collapses every one of those lines, and the only thing the dual path still buys you is compatibility with legacy DASH players that haven't been updated since 2018. For a new streaming service launching in 2026, encrypting twice is undertaking ongoing cost for a problem that no longer exists.

The one wrinkle worth knowing about: the DASH-IF guidelines still permit the dual-encryption case where the same period offers both schemes as equal alternatives for different client capabilities. That is rarely deployed in practice — most modern players speak cbcs natively — but the standard leaves the door open.

A Worked Example: Encrypting a Single CMAF Stream

Let's run the numbers on one segment to make the byte-level economics concrete. Take a single 4-second CMAF video segment at 1080p H.264, roughly 2.5 megabits per second, which means about 1.25 megabytes per segment.

Inside that segment there are roughly 120 video samples (one per frame at 30 frames per second). Each sample contains a few NAL units; for H.264 the encrypted range covers only the slice-data portion of each VCL NAL unit, leaving the NAL header byte and the SEI/SPS/PPS structural NALs in the clear. The encrypted range per sample is on the order of 6 to 12 kilobytes for a 1080p frame.

Under cenc, every 16-byte block inside that 6–12 KB range goes through an AES-128 CTR round — roughly 400 to 750 AES rounds per sample, or 48,000 to 90,000 AES rounds per segment. Modern CPUs and GPU video pipelines hit AES-NI hardware acceleration for this; a Cortex-A53 in a five-year-old smart TV does it in software and pays a real CPU bill.

Under cbcs, the pattern is crypt_byte_block = 1, skip_byte_block = 9, so out of every ten 16-byte blocks only the first is encrypted. The same 6–12 KB encrypted range now needs only 40 to 75 AES rounds per sample — about one-tenth the cenc work. Total per segment: 4,800 to 9,000 AES rounds. On a low-end smart TV this is the difference between dropping frames and keeping pace with the video clock.

A note on initialisation vectors: under cenc, the IV is constructed per sample from a base IV in the tenc box plus a per-block counter; under cbcs, the IV is a fixed per-sample 16-byte value carried in the senc box and applied to each pattern's first encrypted block. The senc box also tells the CDM where each subsample's encrypted range starts and ends, so the CDM can skip the in-the-clear NAL headers without parsing the H.264 bitstream itself.

That last point matters in production: because the CDM operates only on encrypted byte ranges and never parses the codec, it works equally well for H.264, H.265, AV1, and any future codec — the codec parser doesn't have to be DRM-aware. CENC's neutrality across codecs is one of the reasons it survived the AV1 transition unchanged.

How CENC Shows Up in Your Manifest

When you debug a real stream, you see CENC through the manifests, not the binary boxes. Here is what the signalling looks like in each protocol.

In an MPEG-DASH MPD, every encrypted adaptation set carries at least two elements. The first uses schemeIdUri="urn:mpeg:dash:mp4protection:2011", declares the protection scheme in its value attribute (cbcs or cenc), and carries the cenc:default_KID attribute that names the content key. The second and third use schemeIdUri="urn:uuid:" with the DRM's System ID, plus a cenc:pssh child element holding the base-64-encoded pssh box content. A typical 2026 stream has three such elements — one for the generic CENC declaration, one for Widevine, one for PlayReady — and a fourth with FairPlay-specific signalling for the HLS sibling. The DASH-IF Implementation Guidelines for Security specify that this descriptor SHALL be defined on the adaptation-set level, not on individual representations.

In an HLS multi-variant playlist, encryption is signalled through EXT-X-KEY tags inside each variant's media playlist. The two methods you will see are METHOD=SAMPLE-AES (used for both legacy MPEG-TS-in-HLS with FairPlay and modern fMP4-in-HLS with cbcs) and METHOD=SAMPLE-AES-CTR (used for fMP4-in-HLS with cenc — rare in 2026). The KEYFORMAT attribute names the DRM: com.apple.streamingkeydelivery for FairPlay, urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed for Widevine (when supported by hls.js), and so on. The URI attribute names the license-server endpoint — or, more commonly, a small token-bearing prefix that the player passes to the platform's license-server-helper API.

In CMAF, the encryption is in the fMP4 box hierarchy described above. The same CMAF segment serves both HLS and DASH because the binary box structure is one and the same — only the manifest sitting on top differs.

The EXT-X-SESSION-KEY tag, added in HLS 2nd edition (RFC 8216bis), lets a multi-variant playlist declare its keys once at the top rather than repeating them in every variant. Modern HLS authors use it to advertise the same content key across every rendition in an adaptation set, mirroring how DASH puts protection signalling at the adaptation-set level.

Comparison: cenc vs cbcs in Practice

Propertycenc (AES-CTR full-subsample)cbcs (AES-CBC pattern 1:9)
Block-cipher modeCTR (counter)CBC (cipher-block-chaining)
Encryption patternAll blocks of each subsample1 of every 10 blocks
Random accessNative (CTR is parallelisable)Pattern + IV per sample makes it tractable
FairPlay supportNoYes (only mode FairPlay accepts)
Widevine supportYes (legacy default)Yes (since v15 / 2018)
PlayReady supportYesYes (since v4.2 / 2019)
Typical AES rounds (1080p frame)400–750 per sample40–75 per sample
HLS signallingMETHOD=SAMPLE-AES-CTR (rare)METHOD=SAMPLE-AES
DASH signallingvalue="cenc"value="cbcs"
2026 deployment statusLegacy DASH-onlyProduction default everywhere
The single-cell takeaway: pick cbcs for any new pipeline. Pick cenc only if you have an existing DASH-only pipeline whose players you cannot update.

Common Mistakes and Pitfalls

We see the same four mistakes in production over and over. They are worth listing because each one has cost a customer a release week to find.

1. Encrypting with cenc and discovering FairPlay later. A team launches a DASH-only OTT product, encrypts the catalogue with cenc, ships it, and then learns from the iOS app review that Safari and tvOS need FairPlay. FairPlay does not decrypt cenc. The recovery is to re-encrypt every encoded asset in cbcs, which doubles storage for as long as both copies live and triples the time to ship to iOS. The right answer at packaging time is cbcs by default; the wrong answer is to defer the iOS decision until after the catalogue is already encrypted.

2. Putting the default_KID in big-endian in the tenc box and little-endian in the manifest. Some Windows libraries use a "Microsoft GUID" byte order for the first three groups of a UUID — the first 4 bytes, next 2 bytes, and following 2 bytes are written little-endian, the rest big-endian. The DASH-IF guidelines require the same byte order in both the binary tenc box and the string-form cenc:default_KID attribute. Mix them and the license server returns the wrong key, the CDM decrypts to garbage, and the player either shows a black screen or a MEDIA_ERR_DECODE with no diagnostic. The fix is one line in the packager's GUID-serialisation code, but it usually takes a day to find.

3. Writing pssh boxes only into the moov and forgetting the manifest. Older guidance recommended moov/pssh boxes inside the init segment. Current DASH-IF guidance puts the pssh data in the MPD's element under cenc:pssh, because manifests are cheaper to update than init segments. If your team adds a new DRM (say PlayReady on top of an existing Widevine/FairPlay launch) and rewrites the init segments instead of updating the manifests, every cached init segment at every CDN edge has to be invalidated — a multi-day cache-bleed that the manifest-level fix avoids entirely.

4. Using the same content key across the entire catalogue. It is technically legal to encrypt every asset with the same K and the same default_KID. It is also a single point of failure: if K leaks once, the whole library is decrypted, and revocation through DRM policy is much harder than rotating keys per title or per episode. The MPA-aligned content-protection guidelines recommend a fresh content key per title at minimum, and per period (typically a few hours of live, or a day of VOD) is better. Modern KMSs make per-title keys cheap; do that.

Where Fora Soft Fits In

We build the encryption-and-DRM layer into video products across video streaming, OTT and Internet TV, telemedicine, video conferencing, e-learning, and video surveillance. The pattern is always the same: pick a packager that supports CMAF + cbcs (we have shipped with Shaka Packager, Bento4, AWS MediaPackage, and Unified Streaming in production), wire it to a Content Protection Information Exchange (CPIX)-speaking key-management system, point the players at a managed multi-DRM license-server vendor, and integrate the license-server endpoint into the product's session-token model. The encryption itself is two configuration flags in a modern packager; the work is in the policy layer above it — geo-rules, output-protection rules, session expiry, persistent vs streaming licences — and that is where we spend the engineering time on every paid streaming launch.

A decision tree for choosing cenc versus cbcs in 2026, with the cbcs branch as the default and cenc as a legacy-only fallback Figure 4. Choosing the protection scheme in 2026 — cbcs is the default; cenc is a legacy edge case.

What to Read Next

Talk to Us · See Our Work · Download

  • Talk to a streaming engineer. Walk us through your DRM scope and we'll size the packager-and-license-server integration in one call.
  • See our case studies. Real OTT, conferencing, and e-learning products we have shipped — see our portfolio.
  • Download the CENC Quick-Reference PDF. One-page reference: the two production schemes, the four metadata boxes, the three DRM System IDs, and the common pitfalls.

References

  1. ISO/IEC 23001-7:2023Information technology — MPEG systems technologies — Part 7: Common encryption in ISO base media file format files, 3rd edition (December 2023). The controlling specification for CENC; defines the four protection schemes and the pssh, tenc, schm, senc, saiz, saio boxes. . Tier-1 normative source; supersedes the 2016 edition referenced by older W3C documents.
  2. ISO/IEC 14496-12:2022ISO Base Media File Format, 8th edition. The base container CENC layers onto; defines the moov / trak / moof box hierarchy. . Tier-1 normative source.
  3. ISO/IEC 23000-19:2024Common Media Application Format (CMAF) for segmented media, 3rd edition. The CMAF packaging the 2026 default builds on. . Tier-1 normative source.
  4. W3C "cenc" Initialization Data Format — Group Note, 18 July 2024. Defines the Common SystemID 1077efec-c0b2-4d02-ace3-3c1e52e2fb4b and the EME initialization-data flow. . Tier-1 W3C source.
  5. W3C Encrypted Media Extensions — W3C Recommendation, 18 September 2017; Working Draft 21 August 2025. The browser-side API that ties CENC-encrypted media to a CDM. . Tier-1 W3C source.
  6. DASH-IF Implementation Guidelines for SecurityGuidelines-Security, current master (2025). Defines the manifest-side signalling for cenc vs cbcs, the cenc:default_KID attribute, and the pssh-in-MPD convention. . Tier-1 industry profile source.
  7. DASH-IF Identifier Registry — content-protection System IDs. Authoritative list of DRM-vendor UUIDs used in pssh boxes. . Tier-1 registry.
  8. IETF draft-pantos-hls-rfc8216bis-16HTTP Live Streaming 2nd Edition, January 2026. Defines EXT-X-KEY methods SAMPLE-AES and SAMPLE-AES-CTR and their fMP4/CMAF mapping. . Tier-1 IETF source; supersedes RFC 8216 (the original 2017 HLS RFC).
  9. Apple HLS Authoring Specification — revision 2025-09. Defines the FairPlay-compatible cbcs signalling and the SAMPLE-AES profile for fMP4-in-HLS. . Tier-1 Apple source.
  10. W3C ISO Common Encryption ('cenc') Protection Scheme for ISO Base Media File Format Stream Format — Group Note. The stream-format registry entry that ties EME to CENC. . Tier-1 W3C source.