Decrypting And Combining .ts Audio Files with .m3u8

Recent versions of ffmpeg should be able to decrypt the AES-128 HLS streams. You don't need a webserver. If the m3u8 URIs/paths are wrong you can:

  • create a directory
  • copy the key to a key file, ie my.key, and place it in the dir. Note that keys can be rotated, if the playlist has multiple keys copy all of them to different files.
  • copy all .ts segments to the same dir
  • copy and edit the playlist.m3u8 and use just the filename(s) for the key(s) URI(s) and segments.
  • to obtain a single .ts file do:

    ffmpeg -i playlist.m3u8 -c copy output.ts
    
  • if you want just the audio stream without the .ts container you can extract it. Eg: assuming you have a single audio stream using the AAC codec run:

    ffmpeg -i playlist.m3u8 -map 0:a -c copy output.aac
    

This will extract the AAC stream to a file without re-encoding. If you want a codec different than your source you will have to re-encode.

If for some reason you have to use openssl to decrypt the segments keep in mind that if no IV is specified then the IV is equal to the segment's media sequence, ie. the first segment has IV=0, the second has IV=1 and so on. After decryption update the playlist to point the decrypted segments and remove the EXT-X-KEY line. If you go this route you don't even need ffmpeg to obtain a single .ts file as MPEG-TS is directly concatenable, ie. you can just use cat on the decrypted segments.


I've had few free hours today and toyed with this. Long story short - that base64 key is AES encrypted. This additional encryption is done with key which is dynamically generated from device data... meaning that even if I have whole data folder from your device I wouldn't be able to decrypt it.

Now, when you posses rooted device with offline data that's another matter - you can obviously inject your code to intercept key when it's decrypted so content can start playing... which is how I got it.

When you have proper key, decryption and joining of *.ts files is trivial. I recommend that you use FFMPEG for this task, my C# code that I'm leaving for illustration works well works only in some cases (depending on how files are encoded):

var folder = "path_to_folder";
byte[] encryptionKey = File.ReadAllBytes(folder + "path_to_key.key");

var outputFile = "c:\\i_love_you_guys.ts";
using (FileStream outputFileStream = new FileStream(outputFile, FileMode.Create))
{
    var files = Directory.GetFiles(folder, "*.ts");
    for (int i = 0; i < files.Length; i++)
    {
        byte[] encryptionIV = new byte[16];
        using (FileStream inputFileStream = new FileStream(files[i], FileMode.Open))
        {
            using (var aes = new AesManaged { Key = encryptionKey, IV = encryptionIV, Mode = CipherMode.CBC })
            using (var encryptor = aes.CreateDecryptor())
            using (var cryptoStream = new CryptoStream(inputFileStream, encryptor, CryptoStreamMode.Read))
            {
                cryptoStream.CopyTo(outputFileStream);
            }
        }
    }
}

So, this turned out to be wild goose chase. What @aergistal says in his answer is completely valid as long as you have proper my.key. Thus focus on obtaining key in plain format and decryption will then be super easy.