使用OpenSSL加密AES-128 ClearKey HLS分片遇解密失败问题求助
AES-128 ClearKey加密MP4分片HLS失败排查
操作流程
- 拿到生产环境生成的MP4格式HLS分片(无法控制分片生成过程)
- 执行加密命令,试图用IV=0和密钥
aaaaaaaaaaaaaaaa加密所有分片:find . -type f -name "*.mp4" -exec openssl aes-128-cbc -e -in {} -out {}.enc -p -nosalt -iv 00000000000000000000000000000000 -K 97979797979797979797979797979797 \; -exec mv {}.enc {} \; - 编辑.m3u8文件,添加密钥配置:
#EXT-X-KEY:METHOD=AES-128,URI="https://www.myKeyServer.com/key.key",IV=0x00000000000000000000000000000000 - 在HLS测试播放器中验证效果
错误现象
- 播放器1报错:
Failed to find demuxer by probing fragment data, audio_und_2c_128k_aac_1.mp4 - 播放器2报错:
ERROR_DECRYPTING - 密钥服务器返回内容为明文字符串:
aaaaaaaaaaaaaaaa
补充尝试
编写Python脚本批量加密分片,代码如下,但问题依旧:
import os import subprocess ENC_KEY = f"{ord('a')}"*16 print (ENC_KEY) # Loop through all .mp4 files in the current directory video_files = [] audio_files = [] for file in os.listdir(): if not file.endswith(".mp4"): continue if "audio" in file: audio_files.append(file) if "video" in file: video_files.append(file) video_files.sort() audio_files.sort() i = 0 iv = f"{i:032x}" print ("video_files:", video_files) print ("audio_files:", audio_files) # Encrypt the init def init_enc(files, iv): for f_name in files: if not "init" in f_name: continue orig = os.path.join("/app/tstEncription/output_files", f_name) enc = os.path.join("/app/tstEncription/output_files", f_name + "_enc") print (enc) subprocess.run(["openssl", "aes-128-cbc", "-e", "-in", orig, "-out", enc, "-nosalt", "-iv", iv, "-K", ENC_KEY]) init_enc(video_files, iv) init_enc(audio_files, iv) def enc_files(files, _i): i = _i iv = f"{i:032x}" for f_name in files: if "init" in f_name: continue orig = os.path.join("/app/tstEncription/output_files", f_name) enc = os.path.join("/app/tstEncription/output_files", f_name + "_enc") print (enc) subprocess.run(["openssl", "aes-128-cbc", "-e", "-in", orig, "-out", enc, "-nosalt", "-iv", iv, "-K", ENC_KEY]) i = i + 1 iv = f"{i:032x}" enc_files(video_files, 1) enc_files(audio_files, 1)
错误原因及修复方案
1. 密钥格式完全错误
加密时使用的是十六进制格式的密钥(9797...,对应16个ASCII字符a的十六进制值),但密钥服务器返回的是明文字符串aaaaaaaaaaaaaaaa,而HLS要求AES-128密钥必须是16字节的二进制原始数据,不是文本字符串。
修复:
- 调整密钥服务器返回格式,直接返回16字节的二进制数据(即字节流
b"aaaaaaaaaaaaaaaa"),而非文本。 - 若用文件存储密钥,需用二进制模式写入:
open("key.key", "wb").write(b"aaaaaaaaaaaaaaaa")。
2. 错误加密了整个MP4文件
HLS对MP4分片加密时,只能加密媒体数据(mdat box),必须保留moov、moof等容器元数据为明文。用OpenSSL直接加密整个MP4文件会把容器头也加密,导致播放器无法解析分片结构,出现“找不到解复用器”的错误。
修复:
- 使用专门的MP4加密工具,比如MP4Box:
MP4Box -crypt aes-128:key=97979797979797979797979797979797:iv=00000000000000000000000000000000 input.mp4 -output output.mp4 - 或者用ffmpeg:
ffmpeg -i input.mp4 -c copy -encryption_scheme cenc-aes-128 -encryption_key 97979797979797979797979797979797 -encryption_iv 00000000000000000000000000000000 output.mp4
3. IV使用不符合规范(可选但推荐)
虽然用同一个IV不会直接导致解密失败,但HLS规范推荐每个分片使用唯一IV,复用IV存在安全风险。若不同分片使用不同IV,必须在m3u8中为每个分片指定对应的IV(通过EXT-X-KEY的IV字段或EXT-X-MAP中的IV)。
4. 脚本密钥参数验证
脚本中ENC_KEY = f"{ord('a')}"*16生成的字符串9797...(32个字符)与命令行-K参数值一致,这部分是正确的,问题核心仍为密钥服务器返回格式和加密范围错误。
内容的提问来源于stack exchange,提问作者j.derek
相关产品推荐
相关产品推荐

