提示

返回博客列表

下载的 m3u8 是加密的?手把手解密 AES-128 并转为本地可播视频

下载的 m3u8 是加密的?手把手解密 AES-128 并转为本地可播视频

从某些站点扒下来的 m3u8,合并 TS 后却是一堆乱码、播放器报"无法解码"。十有八九是 AES-128 加密——m3u8 文件里用 #EXT-X-KEY 指明了密钥位置和方式,这些 TS 切片是用同一把密钥加过密的。这篇文章把加密原理、密钥获取、逐片解密、批量本地化、以及常见坑一次讲透,让你能把加密 m3u8 变成普通的本地视频。

一、m3u8 里的加密长什么样

打开 m3u8,你会看到类似:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-KEY:METHOD=AES-128,URI="key.key",IV=0x1a2b3c4d5e6f70819283746556473829
#EXTINF:4.0,
seg0.ts
#EXTINF:4.0,
seg1.ts

含义:

  • METHOD=AES-128:用 AES-128 的 CBC 模式加密每个 TS 切片;
  • URI:密钥文件地址(16 字节);
  • IV:初始化向量(16 字节),没有的话默认用分片序号当 IV。

注意:这是"流加密"级别的防护,密钥就明晃晃写在 m3u8 里(或能直接下载),所以它防的是"直接右键另存为拿到明文",不是真正的版权保护(那是 Widevine 的活)。

二、第一步:拿到密钥

密钥通常和 m3u8 同目录,相对路径拼上基地址下载:

curl -O https://example.com/path/key.key

确认它正好 16 字节:wc -c key.key 应显示 16。若 URI 是远程且需要鉴权(带 cookie/referer),下载 key 时一并带上对应请求头。

三、第二步:逐片解密(openssl)

用 openssl 对每片 TS 解密:

openssl aes-128-cbc -d \
  -in seg0.ts -out seg0_dec.ts \
  -K $(xxd -p key.key) \
  -iv 1a2b3c4d5e6f70819283746556473829
  • -K 要密钥的十六进制串(不是文件本身),xxd -p key.key 把二进制转十六进制;
  • -iv 是 IV 的十六进制;
  • 若 m3u8 没写 IV,通常 IV 等于分片序号的 16 进制(seg0 → 00000000000000000000000000000000,seg1 → 00000000000000000000000000000001...)。

四、更省事:直接交给 ffmpeg

ffmpeg 能读带 #EXT-X-KEY 的 m3u8 并一步解密合并——只要密钥 URL 还能访问:

ffmpeg -i "https://example.com/path/index.m3u8" -c copy out.mp4

如果密钥是本地文件,把 m3u8 里的 URI 改成相对路径再喂给 ffmpeg 即可。

五、第三步:改 m3u8 指向本地,完全离线

把 m3u8 下载到本地,把所有远程前缀去掉/改成本地相对路径,TS 切片和 key 也下到同目录,就能离线播放和二次处理:

# 下载整个目录(假设静态托管)
wget -r -np -R "*.html" https://example.com/path/
# 批量清掉 m3u8 里的绝对路径
sed -i 's#https://example.com/path/##g' index.m3u8
# 解密合并
ffmpeg -i index.m3u8 -c copy local.mp4

六、批量自动化(Python 思路)

把"下载 key + 下载所有 ts + 解密 + 合并"串成脚本:

import requests, subprocess, os

base = 'https://example.com/path/'
key = requests.get(base + 'key.key').content          # 16 字节
open('key.bin', 'wb').write(key)
# 下载 m3u8,解析出 ts 列表
m3u8 = requests.get(base + 'index.m3u8').text
segs = [l for l in m3u8.splitlines() if l and not l.startswith('#')]
for i, seg in enumerate(segs):
    r = requests.get(base + seg)
    open(f'seg_{i}.ts', 'wb').write(r.content)
# 用 ffmpeg 一次性解密合并(key 放同目录,改 m3u8 URI 为 key.bin)
...

熟练后这就是一个迷你下载器。

七、SAMPLE-AES 说明

除了 AES-128(整片加密),还有 SAMPLE-AES:只加密每个样本的部分(如视频的 nalu 载荷),音频不加密。这种处理复杂得多,需要专门工具(如 ffmpeg 配合支持的解密模块或 shaka/ExoPlayer),openssl 逐片解不适用。遇到 #EXT-X-KEY:METHOD=SAMPLE-AES 别用本文方法。

八、常见翻车现场

现象 根因 解法
解密后仍是乱码 IV 不对 试分片序号当 IV,或检查 key 是否 16 字节
ffmpeg 报找不到 key URI 仍是远程且失效 下到本地改 m3u8
只有第一片能播 每片 IV 不同却用了同一个 按 m3u8 里每片 IV 分别解
key 文件要鉴权 需带 cookie/referer 下载 key 时带上对应头
全片黑屏有声音 只解密了视频或顺序错 确认按 m3u8 顺序合并

九、常见问题

Q:解密等于破解 DRM 吗? 不等于。AES-128 在 m3u8 里是明文传密钥,只是防直接下载,能拿到密钥说明它没做真正的版权保护(那是 Widevine 的事)。

Q:解密后能再加密吗? 可以,用 shaka-packager(之前写过)重新打包成带 Clear Key 或 Widevine 保护的格式。

Q:为什么有的 m3u8 没 EXT-X-KEY 但下下来还是乱码? 可能是 SAMPLE-AES,或 TS 本身被其他处理,需具体分析。

Q:能边下边解密吗? 能,下载完每个 ts 立即 openssl 解密再追加到输出文件,省去中间落地。

小结

加密 m3u8 不可怕:找到 #EXT-X-KEY 拿到 16 字节 key 和 IV,用 openssl 或 ffmpeg 逐片/一次性解密,再合并成普通视频即可。记住它防的是"随手下载",不是真版权——真正的高级保护在 Widevine 那一层。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部