Skip to main content
 首页 » 编程设计

android之格式错误的加密 mp3 到 m3u8

2025年05月04日32arxive

我有一个将 mp3 编码为 m3u8 的 python 函数。这个功能允许我 生成一个 m3u8 文件及其 ts block 。

我可以使用 iO 上的 native 播放器阅读此“播放列表”。 不幸的是,我无法使用 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 个字符的字符串格式。

您的代码仅以十六进制形式返回数字,但以 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'