Problems decrypting HTTP Live Stream - http

I have a single key encrypted HTTP Live Stream which decodes fine in Quicktime and iPhone. I'm trying to create a simple client application to do the decryption of the ts files. Right now I've used openssl to decrypt. I believe I have the correct arguments to openssl and I'm inserting the key and the IV properly. I can successfully decrypt the first .ts file in the stream but fail to decrypt after. I'm using the following script which I found in the archives here and I reversed to do decryption:
#!/bin/sh
hexKey=$(cat encryption.key | hexdump-e '16/1 "%02x"')
hexIV='00000000000000000000000000000001'
openssl aes-128-cbc -d -in ./multi_2.ts -out ./clear.ts -p-nosalt -iv ${hexIV} -K ${hexKey}
where:
encryption.key is the key file I retrieved from the M3u8 stream file.
multi_2.ts is the second .ts file in the m3u8 stream file.
Any help would be appreciated.

The subsequent .ts files are probably fine, you just need to join them into one file in order to be playable:
cat clear*.ts > joined.ts

hexIV='00000000000000000000000000000001'
should be :
hexIV='00000000000000000000000000000002'
as multi_2.ts is the second .ts file in the m3u8 stream file.

Related

Why do OpenSSl Encription times vary with modifications to file?

I have a ssl wrapper around GNU-Cash which decrypts my data file when opening GNU-Cash, and then re-encrypts it when I exit the app, overwriting the original encrypted file and then deletes the unencrypted one. What happens is if I make say 1 single change in GNU-Cash, the file re-encryption is a second or two, but if I make a lot of changes to the data, then the encryption takes significantly longer. It appears the time to create the new encrypted file is directly related to the changes made in the data file within.
I cannot see why it takes longer to encrypt a heavily modified file than the same one with only minor changes. My script does not remove the original encrypted data, just overwrites it upon exit from GNU-Cash. Does OpenSSl reference the old copy of the encrypted data file which it is over-writing?
I can post the whole thing if needed, but here are the Decrypt and Encrypt lines from the script:
openssl enc -d -aes-256-cbc -pbkdf2 -in ${DATA_FILE} -out ${DECRYPTED_FILE} -pass stdin <<EOPW &> /dev/null
${FILEPASS}
EOPW
openssl enc -e -aes-256-cbc -pbkdf2 -in ${DECRYPTED_FILE} -out ${DATA_FILE} -pass stdin <<EOPW &> /dev/null
${FILEPASS}
EOPW
Thanks.

FFmpeg concat demuxer and handling encrypted chunks

I'm trying to process a remote m3u8 playlist containing (a possibly encrypted) HLS stream. The output I'm looking for is a mp4 container with MPEG-4 inside.
The playlist is a result of an ended live stream and may contain EXT-X-DISCONTINUITY tags. As I understand, there's no "built-in" way to process it and indeed, there are plenty of warnings like "Non-monotonous DTS in output stream" and the resulting file always has some playback issues.
There are a couple of options to "glue" it. On an unencrypted stream, I found concat demuxer to produce the result with the least playback problems. The command is:
LIST=chunks.list; ffmpeg -loglevel 'debug' -f concat -safe 0 -protocol_whitelist "file,http,https,tcp,tls,crypto" -i $LIST -c copy -movflags frag_keyframe -y output_concat.mp4
where chunks.list is something like:
file 'https://www.example.org/chunk1.ts'
file 'https://www.example.org/chunk2.ts'
file 'https://www.example.org/chunk3.ts'
Now, I'm trying to use concat demuxer to process encrypted chunks. I've tried passing -key and -iv options in different places and changing chunks.list to be like file 'crypto+https...' but it won't pick up encryption key:
Opening an input file: chunks.list.
[concat # 0x7f9fb6800c00] Opening 'chunks.list' for reading
[NULL # 0x7f9fb6007e00] Opening 'crypto+https://www.example.org/chunk1.ts' for reading
[crypto # 0x7f9fb5700a00] decryption key not set
[concat # 0x7f9fb6800c00] Impossible to open 'crypto+https://www.example.org/chunk1.ts'
[AVIOContext # 0x7f9fb5700780] Statistics: 5094 bytes read, 0 seeks
chunks.list: Invalid argument
Docs mention encryption options for crypto protocol, so it looks it's just a matter of passing these in a proper way.
When, instead of using concat demuxer, I try to process and decrypt only one chunk like:
ffmpeg -i crypto+https://www.example.org/chunk1.ts -key <my_hex_key> -iv <my_iv> chunk1.ts it works fine. There's nothing wrong with the key itself, I'm able to decrypt it with other tools (openssl etc).
Is it possible for concat demuxer to handle decryption? If so, where should I pass key and iv options?

Error "EVP_DecryptFinal_ex:bad decrypt:crypto\evp\evp_enc.c:570" appears even after specifying -md5 sha256 in command line

I have the following query. Could anyone please suggest me a solution.
I'm working on decryption of .ts file for the first time. I have downloaded multiple .ts files from the source and have merged them but not able to decrypt the file. Even if it gets decrypted the size of the file is zero bytes.
Command I'm using:
aes-128-cbc -d -in D:\Test\joined_files.ts -out D:\Test\decrypt_I00100000.ts -iv 0 -K 313863756468736b63646b6a616b -md SHA256
The error I'm getting:
the hex string is too short, padding with zero bytes to the length
the hex string is too short, padding with zero bytes to the length
bad decrypt
1132:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:crypto\evp\evp_enc.c:570:
error in aes-128-cbc
enter image description here

FFMPEG Encryption

I am doing a project with encrypting
video and I have a few questions for the procedure.
I used a command to transcode mp4 to HLS with a ts segment duration of ~10 seconds.
First, I need to encrypt those videos with a key from database. However,
I have no idea for the encryption whether working with ffmpeg or not.
Second, if the encryption can work without ffmpeg, so what should I do? I have searched in google which includes something like openssl / aes but
there is no a detailed step for me to follow, even the ffmpeg link:
http://www.ffmpeg.org/ffmpeg-all.html#srtp
Could anyone give me a hand, teaching me how to encrypt a video? Thanks to you.
Yes, you can do it with ffmpeg. You need to write the key from the database to a file, let's say video.key.
You need a second file, let's name it key_info which is the key info file. It has the following format:
key URI
key file path
IV (optional)
Eg:
http://example.com/video.key
video.key
You tell ffmpeg to use it to encrypt your segments with the hls_key_info argument:
ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -hls_time 10 -hls_key_info_file key_info playlist.m3u8
This will encrypt your segments with AES-128 in CBC mode and add the relevant tags to your playlist:
#EXT-X-KEY:METHOD=AES-128,URI="http://example.com/video.key"
You can also manually encrypt the segments if you want with openssl. Here's an example script, where each IV is equal to the segment index:
#!/bin/bash
ts_dir=/path/to/ts/
key_file=video.key
openssl rand 16 > $key_file
enc_key=$(hexdump -v -e '16/1 "%02x"' $key_file)
pushd $ts_dir
ts_cnt=$(ls *.ts | wc -l)
((ts_cnt--))
i=0
for i in $(seq -f "%01g" 0 $ts_cnt); do
iv=$(printf '%032x' $i)
ts_file=segment-$i.ts
echo [$i] $ts_file
openssl aes-128-cbc -e -in $ts_file -out encrypted_${ts_file} -nosalt -iv $iv -K $enc_key
done
popd

How to decrypt AES-128 encrypted m3u8 video files?

I trying to decrypt AES-128 encrypted m3u8 video files such as this one :
the m3u8 file :
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:NO
#EXT-X-VERSION:2
#EXT-X-FAXS-CM:MII6lAYJKoZIhvcNAQcCoII6hTCCOoECAQExCzAJBgUrDgMCGgUAM... very long key...
#EXT-X-KEY:METHOD=AES-128,URI="faxs://faxs.adobe.com",IV=0X99b74007b6254e4bd1c6e03631cad15b
#EXT-X-TARGETDURATION:8
#EXTINF:8,
video.mp4Frag1Num0.ts
#EXTINF:8,
video.mp4Frag1Num1.ts
...
I've tried with openssl :
openssl aes-128-cbc -d -kfile key.txt -iv 99b74007b6254e4bd1c6e03631cad15b -nosalt -in video_enc.ts -out video_dec.ts
key.txt contains the very long key
-->
bad decrypt
1074529488:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:539:
What am-I doing wrong ?
This might be a bit of a hack, but given a URL to an .m3u8 file, it will download and decrypt the files that make up the stream:
#!/usr/bin/env bash
curl "$1" -s | awk 'BEGIN {c=0} $0 ~ "EXT-X-KEY" {urlpos=index($0,"URI=")+5; ivpos=index($0,"IV="); keyurl=substr($0, urlpos, ivpos-urlpos-2); iv=substr($0, ivpos+5); print "key=`curl -s '\''"keyurl"'\'' | hexdump -C | head -1 | sed \"s/00000000//;s/|.*//;s/ //g\"`"; print "iv="iv} $0 !~ "-KEY" && $0 ~ "http" {printf("curl -s '\''"$0"'\'' | openssl aes-128-cbc -K $key -iv $iv -d >seg%05i.ts\n", c++)}' | bash
This script generates a second script that extracts keys and initialization vectors and uses them to decrypt while downloading. It needs curl, awk, hexdump, sed, and openssl to run. It'll probably choke on an unencrypted stream, or on a stream that uses something other than AES-128 (is any other encryption supported?).
You'll get a bunch of files: seg00000.ts, seg00001.ts, etc. Use tsMuxeR (https://www.videohelp.com/software/tsMuxeR) to merge these into a single file (simple concatenation didn't work for me...it's what I tried first):
(echo "MUXOPT --no-pcr-on-video-pid --new-audio-pes --vbr --vbv-len=500"; (echo -n "V_MPEG4/ISO/AVC, "; for i in seg*.ts; do echo -n "\"$i\"+"; done; echo ", fps=30, insertSEI, contSPS, track=258") | sed "s/+,/,/"; (echo -n "A_AAC, "; for i in seg*.ts; do echo -n "\"$i\"+"; done; echo ", track=257") | sed "s/+,/,/") >video.meta
tsMuxeR video.meta video.ts
(Track IDs and framerate may need adjustment...get the values to use by passing one of the downloaded files to tsMuxeR.)
Then use ffmpeg to remux to something a bit more widely understood:
ffmpeg -i video.ts -vcodec copy -acodec copy video.m4v
In order to decrypt encrypted video stream you need encryption key.
This key is not part of the stream. It should be obtained separately.
EXT-X-FAXS-CM header contains DRM meta-data and not the key.
This is excert from Adobe Media Server developer guide:
The Adobe Access Server protected variant playlist also needs to include the #EXT-X-FAXS-CM tag. The value of #EXT-X-FAXS-CM tag in variant playlist is the relative URI referring to the DRM metadata of one of the individual streams.At the client, the #EXT-X-FAXS-CM tag in variant playlist will be used to create the DRM session. The same DRM session will be used for all encrypted M3U8 files inside the variant playlist.
Full guide can be found here:
http://help.adobe.com/en_US/adobemediaserver/devguide/WS5262178513756206-4b6aabd1378392bb59-7fe8.html
There is also mention that faxs://faxs.adobe.com URI is for local key serving.
So key obtained locally from a device.
While some of the bash scripts in the existing answers get you part (or even all) of the way, depending which site you're trying to download from, you might hit other obstacles (different auth method, custom license server mount, etc.)
I've found streamlink to be the most robust solution for this, which also lets you stream directly (rather than download), if that's what you're after, and it has all the site-specific work already done for you for a long list of sites (see plugins section, but keep in mind it's under active development and the latest release was in June, so for some of the newer ones you'll have to git clone and install from source).
In many cases, VLC will happily convert an .m3u8 video to an unencrypted .ts or .mp4. In the VLC graphical interface, go to Media > Convert/Save.
Even through this file includes AES encrypted data, openssl don't know the m3u8 format. However FFmpeg might be able to handle it.

Resources