格式错误的加密 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'