Stream Video Downloader logo
← Back to Blog

How HLS Segment Encryption Works: AES-128 Keys, IVs, and Where DRM Draws the Line

July 8, 2026 · 6 min read

A lot of HLS playlists carry a line that looks like this: #EXT-X-KEY:METHOD=AES-128,URI="key.bin",IV=0x.... It shows up right before the segment list in a media playlist, and it means every segment that follows is encrypted. That single tag gets treated as a wall — "encrypted, so not downloadable" — when in practice it's one of the lighter forms of stream protection, and understanding exactly what it does (and doesn't do) explains why some "encrypted" streams are perfectly downloadable while others, despite looking similar in the playlist, never will be.

What the tag actually specifies

#EXT-X-KEY has three attributes that matter for playback: METHOD, URI, and IV. METHOD=AES-128 means each segment is encrypted whole, with standard AES in CBC mode, using a 128-bit (16-byte) key. URI points to where that key lives — almost always a plain HTTPS URL returning the raw 16 bytes of key material, nothing fancier. IVis the 128-bit initialization vector AES-CBC needs alongside the key; if the tag omits it, the spec falls back to using the segment's own sequence number, encoded as a 16-byte big-endian value, so every segment still gets a distinct IV even without one written explicitly into the playlist.

As covered in how HLS streaming works, this tag sits in the media playlist alongside segment URIs and #EXT-X-MAP (the fMP4 initialization segment some streams use). All three — key, init segment, and each media segment — are separate HTTP fetches. Nothing about the playlist format bundles them together; a player (or any other tool reading the playlist) has to go fetch the key file on its own before it can do anything with the segment bytes.

The key request is just another fetch — with the same CORS story

Because the key lives at its own URL, fetching it is subject to exactly the cross-origin rules covered in why CORS blocks video downloads. A page playing the video natively never notices, since the browser's media stack requests the key and hands it straight to the decoder. A tool that instead reads the playlist, resolves the URI attribute, and tries to fetch those 16 bytes itself is making the same kind of cross-origin read as fetching a segment — and hits the same CORS wall if the CDN doesn't allow it. This project's parser resolves the key URI and its IV per segment the same way it resolves segment URLs, and the converterpulls the key bytes through the bridge-first fetch pattern, writes them into ffmpeg's virtual filesystem, and rewrites the playlist's URIto point at that local copy — so ffmpeg's own HLS demuxer does the actual AES-128 decryption while muxing, the same way any compliant HLS player would.

Key rotation changes per segment group, not per byte

A single VOD playlist often has one #EXT-X-KEY tag that applies to the rest of the file. Live streams, and some VOD content split into multiple sections, commonly repeat the tag with a new URIpartway through the segment list — a new key (and usually a new IV) taking over from that point on. Nothing about the HLS format requires this, but it's a common way to limit how much content a single leaked key can unlock, and it means a tool has to actually watch for repeated #EXT-X-KEY lines while walking the playlist rather than assuming the first one it sees covers every segment.

Where this stops being AES-128 and starts being DRM

This is the distinction that matters most: AES-128 (and its sibling METHOD=SAMPLE-AES, which encrypts individual audio/video samples instead of the whole segment) delivers the decryption key in the clear, at a URL any HTTP client can request. Nothing about the scheme stops a script from reading that key file, the way it read the playlist — the protection depends entirely on the CDN not letting the wrong origin fetch it, the same CORS/token machinery covered elsewhere on this site, not on the key itself being unreadable.

Real DRM is a different mechanism entirely. As explained in why Chrome can't play HLS natively, Widevine, PlayReady, and FairPlay route decryption through the Encrypted Media Extensions(EME) API into a platform-level Content Decryption Module — a sandboxed component that negotiates and holds the decryption key itself. Neither the page's JavaScript nor a browser extension's privileged fetch ever sees that key; it never travels as a plain, fetchable file the way an AES-128 key does. A stream protected this way stays protected no matter how freely its encrypted segment bytes can be downloaded, because the bytes alone are useless without a key that was never exposed to anything outside the CDM.

That's the real line between "encrypted but downloadable" and "actually locked down": whether the key is a plain file sitting at a URL in the playlist, or a value that only ever exists inside a CDM sandbox. #EXT-X-KEY with METHOD=AES-128 is almost always the former. As covered in is it legal to download streaming video, circumventing the latter is treated as a separate legal issue from copyright infringement itself — this site's tools only ever fetch a key the same way a browser already does, and only work with streams you own or have permission to access.

FAQ

If I can see #EXT-X-KEY in a playlist, can I always download the video?Not necessarily. The tag only tells you the segments are AES-128/SAMPLE-AES encrypted — whether the key URL itself is fetchable from wherever you're asking depends on the same CORS and access-control rules that govern the segments, and some sites still layer their own token checks on the key request specifically.

Is AES-128 encryption pointless, then?No — it still stops casual scraping of raw segment URLs and adds a real access-control checkpoint (the key fetch) that a site can protect with its own auth, expiry, or CORS rules. It's just a different threat model than DRM, which is built to resist a technically capable attacker who already has full access to the encrypted bytes.

Why do some segments use SAMPLE-AES instead of AES-128? SAMPLE-AES encrypts individual samples within a segment rather than the whole file, which is the format used when HLS carries codecs (like certain audio formats) that need parts of the container left readable for parsing before decryption. Both methods still rely on a key delivered via the same URI/IV mechanism.