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 theAAC
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.