格式错误的加密 mp3 到 m3u8
Malformed encryption mp3 to m3u8
我有一个 python 函数将 mp3 编码为 m3u8。这个功能允许我
生成一个 m3u8 文件及其 ts 块。
我可以在 iOs 上使用本机播放器阅读此 "playlist"。
不幸的是,我无法使用 android-mediaplayer(我收到错误 MEDIA_ERROR_MALFORMED)。
问题是,如果在 python 中,我通过子进程使用 openssl,它就可以工作。但是产生一个新进程太昂贵了,我想避免这种情况:
cmd = ["openssl",
"aes-128-cbc",
"-e",
"-in", path,
"-out", dest_path+".openssl.ts",
"-iv", ("%d" % iv_counter).zfill(32),
"-K", keyHex]
subprocess.check_call(cmd)
使用 openssl 或我的实现生成相同的 m3u8 文件,相同数量的 ts 文件并且这些 ts 文件具有完全相同的权重。
我能找到的唯一解释是我的实现是错误的。我知道这可能很难调试,但也许您在第一次阅读时会突然想到一些东西。
这是进行加密的函数:
from Crypto import Random
from Crypto.Cipher import AES
def encrypt(manifest, chunks, enc_dir):
os.makedirs(enc_dir)
# Get a random key
key = Random.new().read(16)
keyHex = key.encode('hex')
# Encrypt each chunk
for iv_counter, (_, path) in enumerate(chunks):
with open(path, "rb") as chunk:
chunk_data = chunk.read()
# PKCS#7 padding
pad = 16 - (len(chunk_data) % 16)
chunk_data += chr(pad) * pad
print "crypting using %s" % ("%d" % iv_counter).zfill(32)
# AES encryption
aes = AES.new(key, AES.MODE_CBC, "%16X" % iv_counter)
chunk_data = aes.encrypt(chunk_data)
dest_path = os.path.join(enc_dir, os.path.basename(path))
#cmd = ["openssl",
# "aes-128-cbc",
# "-e",
# "-in", path,
# "-out", dest_path+".openssl.ts",
# "-iv", ("%d" % iv_counter).zfill(32),
# "-K", keyHex]
#subprocess.check_call(cmd)
with open(dest_path, "wb") as chunk:
chunk.write(chunk_data)
# Write the key to a file
key_file = os.path.join(enc_dir, os.path.splitext(os.path.basename(manifest))[0] + ".key")
with open(key_file, "w") as keyf:
keyf.write(key)
key_url = os.path.basename(key_file) #"file://" + os.path.abspath(key_file)
# Write the new manifest
dest_manifest = os.path.join(enc_dir, os.path.basename(manifest))
with open(dest_manifest, "w") as manifest:
manifest.write("#EXTM3U\n")
manifest.write("#EXT-X-VERSION:3\n")
manifest.write("#EXT-X-MEDIA-SEQUENCE:0\n")
manifest.write("#EXT-X-ALLOW-CACHE:YES\n")
manifest.write("#EXT-X-TARGETDURATION:6\n")
manifest.write("#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"\n" % key_url)
for extinf, path in chunks:
manifest.write("%s\n%s\n" % (extinf, os.path.basename(path)))
manifest.write("#EXT-X-ENDLIST\n")
编辑,如果有帮助的话:我们编写了一个小的 JAVA 函数来解密由 openssl 和我们自制代码生成的 ts 文件。 openssl 生成的文件很好,但我们的 python 代码生成的文件出现了错误的填充异常。
问题出在您的初始向量 (iv) 上。 OpenSSL 正在等待一个数字参数(十六进制),但是是 16 个字符的字符串格式。
您的代码只是 returns 十六进制数字,但采用 ASCII 格式:
>>> iv_counter = 11111111
>>> print("%16X" % iv_counter)
' A98AC7'
然而,期望值是:
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x8a\xc7'
要实现它,您必须将其替换为:
>>> print(("%032X" % iv_counter).decode("hex"))
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x8a\xc7'
我有一个 python 函数将 mp3 编码为 m3u8。这个功能允许我 生成一个 m3u8 文件及其 ts 块。
我可以在 iOs 上使用本机播放器阅读此 "playlist"。 不幸的是,我无法使用 android-mediaplayer(我收到错误 MEDIA_ERROR_MALFORMED)。
问题是,如果在 python 中,我通过子进程使用 openssl,它就可以工作。但是产生一个新进程太昂贵了,我想避免这种情况:
cmd = ["openssl",
"aes-128-cbc",
"-e",
"-in", path,
"-out", dest_path+".openssl.ts",
"-iv", ("%d" % iv_counter).zfill(32),
"-K", keyHex]
subprocess.check_call(cmd)
使用 openssl 或我的实现生成相同的 m3u8 文件,相同数量的 ts 文件并且这些 ts 文件具有完全相同的权重。
我能找到的唯一解释是我的实现是错误的。我知道这可能很难调试,但也许您在第一次阅读时会突然想到一些东西。 这是进行加密的函数:
from Crypto import Random
from Crypto.Cipher import AES
def encrypt(manifest, chunks, enc_dir):
os.makedirs(enc_dir)
# Get a random key
key = Random.new().read(16)
keyHex = key.encode('hex')
# Encrypt each chunk
for iv_counter, (_, path) in enumerate(chunks):
with open(path, "rb") as chunk:
chunk_data = chunk.read()
# PKCS#7 padding
pad = 16 - (len(chunk_data) % 16)
chunk_data += chr(pad) * pad
print "crypting using %s" % ("%d" % iv_counter).zfill(32)
# AES encryption
aes = AES.new(key, AES.MODE_CBC, "%16X" % iv_counter)
chunk_data = aes.encrypt(chunk_data)
dest_path = os.path.join(enc_dir, os.path.basename(path))
#cmd = ["openssl",
# "aes-128-cbc",
# "-e",
# "-in", path,
# "-out", dest_path+".openssl.ts",
# "-iv", ("%d" % iv_counter).zfill(32),
# "-K", keyHex]
#subprocess.check_call(cmd)
with open(dest_path, "wb") as chunk:
chunk.write(chunk_data)
# Write the key to a file
key_file = os.path.join(enc_dir, os.path.splitext(os.path.basename(manifest))[0] + ".key")
with open(key_file, "w") as keyf:
keyf.write(key)
key_url = os.path.basename(key_file) #"file://" + os.path.abspath(key_file)
# Write the new manifest
dest_manifest = os.path.join(enc_dir, os.path.basename(manifest))
with open(dest_manifest, "w") as manifest:
manifest.write("#EXTM3U\n")
manifest.write("#EXT-X-VERSION:3\n")
manifest.write("#EXT-X-MEDIA-SEQUENCE:0\n")
manifest.write("#EXT-X-ALLOW-CACHE:YES\n")
manifest.write("#EXT-X-TARGETDURATION:6\n")
manifest.write("#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"\n" % key_url)
for extinf, path in chunks:
manifest.write("%s\n%s\n" % (extinf, os.path.basename(path)))
manifest.write("#EXT-X-ENDLIST\n")
编辑,如果有帮助的话:我们编写了一个小的 JAVA 函数来解密由 openssl 和我们自制代码生成的 ts 文件。 openssl 生成的文件很好,但我们的 python 代码生成的文件出现了错误的填充异常。
问题出在您的初始向量 (iv) 上。 OpenSSL 正在等待一个数字参数(十六进制),但是是 16 个字符的字符串格式。
您的代码只是 returns 十六进制数字,但采用 ASCII 格式:
>>> iv_counter = 11111111
>>> print("%16X" % iv_counter)
' A98AC7'
然而,期望值是:
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x8a\xc7'
要实现它,您必须将其替换为:
>>> print(("%032X" % iv_counter).decode("hex"))
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x8a\xc7'