Decrypting And Combining .ts Audio Files with .m3u8

21,123

Solution 1

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.

Solution 2

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.

Share:
21,123
Jonathon
Author by

Jonathon

Updated on May 05, 2020

Comments

  • Jonathon
    Jonathon about 4 years

    I have a few thousand .ts AES-128 encrypted audio files with a .key and .m3u8 file.

    The key file just contains a key comprised of 44 characters. The .m3ud files appears to be some type of playlist.

    #EXTM3U
    #EXT-X-ALLOW-CACHE:NO
    #EXT-X-TARGETDURATION:10
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-KEY:METHOD=AES-128,URI="http://localhost:[port]/hls/keys/nax_9781843794066.key"
    #EXTINF:10,
    http://localhost:[port]/filesequence0000000.ts
    #EXTINF:10,
    etc...
    

    Note that both the key URI and path to the .ts files is now wrong.

    Looking around, it appears ffmpeg might work with this format. But I am unsure of the syntax.

    How can I decrypt and combine these files?

    I have been playing around with fixing the playlist syntax and figuring out how to use ffmpeg and got to.

    ffmpeg -i nax_9781843794066.m3u8 -c copy output.ts
    ffmpeg version N-77197-gdf2ce13 Copyright (c) 2000-2015 the FFmpeg developers
    built with gcc 5.2.0 (GCC)
    configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libdcadec --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-decklink --enable-zlib
    libavutil      55. 10.100 / 55. 10.100
    libavcodec     57. 17.100 / 57. 17.100
    libavformat    57. 19.100 / 57. 19.100
    libavdevice    57.  0.100 / 57.  0.100
    libavfilter     6. 20.100 /  6. 20.100
    libswscale      4.  0.100 /  4.  0.100
    libswresample   2.  0.101 /  2.  0.101
    libpostproc    54.  0.100 / 54.  0.100
    [hls,applehttp @ 0000003e6348a660] Error when loading first segment 'filesequence0000000.ts'
    nax_9781843794066.m3u8: Invalid data found when processing input
    

    filesequence0000000.ts is the first file, in the same folder. I cannot tell if this is some problem with the encryption or something else.

    This is the key file, if it matters: MoOoNvcKlThWBm2T+VzYq9QKZLw7MFUqSyLYjiwquTQ=

  • Jonathon
    Jonathon over 8 years
    great indepth answer. Unfortunately, it does not work. See addendum above. I did exactly what you described and am getting an invalid data error.
  • Jonathon
    Jonathon over 8 years
    That's the file that came off the device, 44 characters/44 bytes. Unless the key is some red herring, that is the key the android application used to decrypt these files for playback.
  • aergistal
    aergistal over 8 years
    Try echo MoOoNvcKlThWBm2T+VzYq9QKZLw7MFUqSyLYjiwquTQ= | base64 --decode > out.key
  • Jonathon
    Jonathon over 8 years
    Yep. looking around I found two interesting things: An AES 256-bit key can be expressed as a hexadecimal string with 64 characters. It will require 44 characters in base64. So maybe this is just pretending it is 128 bit encryption?. Also, it does appear to be encoded in base 64.
  • Jonathon
    Jonathon over 8 years
    OK it went down to 32 bytes, which is what we are apparently looking for. For 128
  • aergistal
    aergistal over 8 years
    It should be 16 bytes for 128. See if it works though.
  • Jonathon
    Jonathon over 8 years
    The decryption seems to be working, but ffmpeg is failing at simply understanding the audio feed from what I am reading. It thinks it is probably aac, but its not sure, then follows millions of errors about improper channel elements and other data it was not expecting to find. And fails. Here is the output pastebin.com/Zea9dsar
  • Jonathon
    Jonathon over 8 years
    Yes, you are right. it is 32 Hexadecimal characters, which would be only 16 normal (and the output is definitely not Hex). So it does appear to be a 256 bit key.
  • aergistal
    aergistal over 8 years
  • Aameer
    Aameer over 7 years
    @aergistal any pointers on how we can rotate the keys (i.e use multiple keys for encryption)? I searched around but couldn't find anything. I know that zencoder.com (app.zencoder.com/docs/api/encoding/encryption/…) does something similar.
  • aergistal
    aergistal over 7 years
    @Aameer see my answer here. The hls_key_info_file is reloaded each time so you just generate a new key in a different file and with a different URL.
  • Aameer
    Aameer over 7 years
    ffmpeg -i sintel_trailer-720p.mp4 -profile:v baseline -level 4.0 -vf "scale=-2:360,subtitles='dynamic_subtitle_test.ass':force_st‌​yle='FontName=common‌​/indee_cloud/Aaargh.‌​ttf,PrimaryColour=&H‌​664c4c4c" -start_number 0 -hls_time 10 -hls_list_size 0 -hls_key_info_file file.keyinfo -f hls test_360_.m3u8
  • Aameer
    Aameer over 7 years
    This is what I am doing and I am able to do the encryption for my playlist with 4 versions (1080,720,480,320) with 4 different keys. But correct me if I am wrong that key_info_file is the same for a particular version(say in this case 360) so it will point to only one key . So how can a key be rotated or changed to another one for the same set of segments ( i am assuming by segments zencoder means .ts segments) ?. Is it even possible to rotate keys even for a set of .ts sections with ffmpeg?
  • aergistal
    aergistal over 7 years
    @Aameer you overwrite hls_key_info_file during the encoding each time you want a new key.
  • nikib3ro
    nikib3ro almost 7 years
    @JonathonWisnoski did you and aergistal managed to solve this? I am trying with another key and it's 32 bytes (like it's 256 bit key). Can you provide me with any pointers? I can upload zip file on which I'm trying to operate if that helps - let me know!
  • aergistal
    aergistal almost 7 years
    @kape123 it's probably the key + iv (each 16 bytes)
  • Jonathon
    Jonathon almost 7 years
    @kape123 Sorry, I gave up. Please post the solution if you ever get it.
  • nikib3ro
    nikib3ro almost 7 years
    @JonathonWisnoski I will... I've tried coding my own utility to decrypt files with Aes128. But the problem is that I need to interpret how that 32 bytes key interacts with IV. It must be something standard considering it's standard m3u8 that depends on Apple HLS. I think the problem also becomes how key interacts with IV... I've tried generating byte[16] IV that's 0,1,2,3 as sequence goes... but couldn't decrypt even that way for some reason with existing 32 byte key. Anyways - will update and hope aergistal will be able to help. Zip with files is online for anyone to try.
  • nikib3ro
    nikib3ro almost 7 years
    @aergistal come on man - we can't give up ;). We have files, playlist, key... there must be some way. I can code utility that transforms key in any way you think it should work. I don't know much about Apple HLS - but is there anything in that standard that talks about 44byte key that's base64 text representation? Because that's key that's supplied by default. I can transform that in any way you see fit through custom utility as long as you explain me how to generate Key and IV values for AES128 decryption of files. Thanks for you help!
  • nikib3ro
    nikib3ro almost 7 years
    @JonathonWisnoski GOT IT. It seems that base64 key is somehow encrypted. I've managed to bypass protection to obtain plain 16 byte key. Once I had key I've used my utility I coded yesterday that easily converts encrypted .ts files into one single decrypted .ts. Weird thing is that this worked with IV that's always 0. Now that I have 16 byte key I'll see if I can figure out how that base64 44 byte key maps into plain 16 byte key. And if I figure it out I'll try to open source my code so that others can learn from my struggle to figure this out ;).
  • aergistal
    aergistal almost 7 years
    @kape123 You and Jonathon are both trying to decrypt audiobooks (the name of the playlist contains the ISBN btw). Both of your keys are similarly generated so it looks like a form of DRM.
  • NateT
    NateT almost 7 years
    @kape123 any hints on how you managed to get the correct 16 byte key?
  • Mohammad Olfatmiri
    Mohammad Olfatmiri over 6 years
    how can i get TS files separately and not a single TS file ?
  • nikib3ro
    nikib3ro over 6 years
    @Oli you can create create multiple streams and have them write to separate files. I.e. move that FileStream outputFileStream creation in for loop.
  • Mohammad Olfatmiri
    Mohammad Olfatmiri over 6 years
    i got this error ' Invalid data found when processing input' whats wrong ?
  • baptx
    baptx over 6 years
    I had to use openssl because ffmpeg / avconv always created videos limited to 30 seconds. For example, if the m3u8 had 5 chunks of 10 seconds, it resulted in 30 seconds only. Also ffmpeg / avconv never exited after the m3u8 conversion was finished, so I had to do Ctrl+C. By the way, is it not possible to launch a TV livestream (HLS m3u8) starting from the last 30 minutes without downloading chunks?