########################################################################################## HLS-20: Reported issues with Encryption ########################################################################################## Issue Type: Bug ----------------------------------------------------------------------------------------- Issue Information ==================== Priority: Major Status: Closed Resolution: Fixed (2017-04-26 22:20:00) Project: HLS Stream Creator (HLS) Reported By: btasker Assigned To: btasker Components: - CLI Options - Encryption Affected Versions: - 1.0 Targeted for fix in version: - 1.0 Labels: Encryption, Time Estimate: 0 minutes Time Logged: 124 minutes ----------------------------------------------------------------------------------------- Issue Description ================== A couple of users have reported (in Github #15) that when they enable encryption, nothing happens An example call provided is -- BEGIN SNIPPET -- ./HLS-Stream-Creator.sh -i trailer.mov -s 10 -e -o trailer -b 272,872,1372,1872 -- END SNIPPET -- When the issue was originally raised I ran a test and it seemed to work, but the original user never provided the further info I asked for. Another user has reported the same issue (in the same thread) and has provided the commandline above, so need to revisit this ----------------------------------------------------------------------------------------- Issue Relations ================ - Caused by HLS-17: PR#7 Added AES-128 encryption to the generated files - relates to HLS-21: Review Encrypt function - Github #15 (https://github.com/bentasker/HLS-Stream-Creator/issues/15) - Original Merge bb3cce4f (https://github.com/bentasker/HLS-Stream-Creator/commit/bb3cce4febdbcc59ca33c304ae34a6168d310169) ----------------------------------------------------------------------------------------- Activity ========== ----------------------------------------------------------------------------------------- 2017-04-26 19:57:35 btasker ----------------------------------------------------------------------------------------- Turns out I still need to update the readme to note the existence of this flag, but the functionality was originally merged in bb3cce4f ----------------------------------------------------------------------------------------- 2017-04-26 20:06:26 btasker ----------------------------------------------------------------------------------------- OK, running a test against the latest master -- BEGIN SNIPPET -- # Looks like I've got an old version of ffmpeg, so will allow experimental codecs for now (and update later) ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ FFMPEG_FLAGS='-strict -2' ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ export FFMPEG_FLAGS # Verifying that it works without encryption ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ./HLS-Stream-Creator.sh -i /tmp/hlstest/big_buck_bunny_720p_stereo.avi -s 10 -o test1 -b 272,872,1372,1872 -- END SNIPPET -- All looks fine so far. Now with encryption enabled -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ./HLS-Stream-Creator.sh -i /tmp/hlstest/big_buck_bunny_720p_stereo.avi -s 10 -e -o test2 -b 272,872,1372,1872 -- END SNIPPET -- That's running, but encryption doesn't happen until the end, so will need to wait for the transcodes to complete. Will have a look over the code while I wait ----------------------------------------------------------------------------------------- 2017-04-26 20:16:27 btasker ----------------------------------------------------------------------------------------- Transcodes have completed, but it doesn't look like encrypt has run at all -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ grep X-KEY test2/*m3u8 ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ls test2/*.key ls: cannot access 'test2/*.key': No such file or directory -- END SNIPPET -- I don't see anything odd on either stdout or stderr I wonder if it might be a weird product of creating an Adaptive stream. Will re-run with a single bitrate and see if encrypt then gets called -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ./HLS-Stream-Creator.sh -i /tmp/hlstest/big_buck_bunny_720p_stereo.avi -s 10 -e -o test3 -b 272 -- END SNIPPET -- ----------------------------------------------------------------------------------------- 2017-04-26 20:26:17 btasker ----------------------------------------------------------------------------------------- Odd, doesn't seem to be happening for a single bitrate stream either -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ls test3/*.key ls: cannot access 'test3/*.key': No such file or directory -- END SNIPPET -- Was definitely working before? ----------------------------------------------------------------------------------------- 2017-04-26 20:30:44 btasker ----------------------------------------------------------------------------------------- Ohhhh, I see it. It's a result of the conditional at Line 353 ( https://github.com/bentasker/HLS-Stream-Creator/blob/4a9e0a019f3eed8036836b37c93e213a03c0fade/HLS-Stream-Creator.sh#L353 ) If bitrates have been specified in the argument list, we fork off down a different code path (because we need to spin up sub-processes etc). Processing effectively ends once awaitCompletion has done it's bit. The call to encrypt happens in the other (smaller) code path, that we follow when bitrates haven't been explicitly specified, essentially everything below the else at line 438 ( https://github.com/bentasker/HLS-Stream-Creator/blob/4a9e0a019f3eed8036836b37c93e213a03c0fade/HLS-Stream-Creator.sh#L438 ) So the original pull request was wrong. Damn, I should've caught that ----------------------------------------------------------------------------------------- 2017-04-26 21:00:00 btasker ----------------------------------------------------------------------------------------- Post "fix" (commit a8898a3) testing Specify a single bitrate on the CL -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ./HLS-Stream-Creator.sh -i /tmp/hlstest/big_buck_bunny_720p_stereo.avi -s 10 -e -o test6 -b 272 ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ls test6/*.key test6/big_buck_bunny_720p_stereo.avi.key -- END SNIPPET -- Not perfect though, the m3u8 rewrite is using an incorrect manifest name -- BEGIN SNIPPET -- sed: can't read test6/big_buck_bunny_720p_stereo.avi.m3u8: No such file or directory -- END SNIPPET -- Thinking about it, the key will need to be written into the bitrate manifests (and not the master) anyway. I'm going to put that into a seperate commit Test with no bitrate specified -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ./HLS-Stream-Creator.sh -i /tmp/hlstest/big_buck_bunny_720p_stereo.avi -s 10 -e -o test7 ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ ls test7/*.key test7/big_buck_bunny_720p_stereo.avi.key ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ grep X-KEY test7/big_buck_bunny_720p_stereo.avi.m3u8 #EXT-X-KEY:METHOD=AES-128,URI=big_buck_bunny_720p_stereo.avi.key -- END SNIPPET -- And (expectedly) no complaints about not being able to find the manifest. Checking playback -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ vlc http://scratch.holly.home/HLS/test7/big_buck_bunny_720p_stereo.avi.m3u8 .... httplive stream error: gcry_cipher_decrypt failed: gcrypt/Invalid length -- END SNIPPET -- Playback fails. Looking in the access logs, VLC is requesting a range -- BEGIN SNIPPET -- 192.168.1.70 - - [26/Apr/2017:20:52:57 +0100] "GET /HLS/test7/big_buck_bunny_720p_stereo.avi.key HTTP/1.1" 206 16 "-" "VLC/2.2.2 LibVLC/2.2.2" 192.168.1.70 - - [26/Apr/2017:20:52:57 +0100] "GET /HLS/test7/big_buck_bunny_720p_stereo.avi_00000.ts HTTP/1.1" 206 3008564 "-" "VLC/2.2.2 LibVLC/2.2.2" 192.168.1.70 - - [26/Apr/2017:20:52:57 +0100] "GET /HLS/test7/big_buck_bunny_720p_stereo.avi.m3u8 HTTP/1.1" 206 3691 "-" "VLC/2.2.2 LibVLC/2.2.2" -- END SNIPPET -- The 206 is just because VLC requests uses "Range: bytes=0-" Getting 16 bytes back, which should be right, the HLS spec says -- BEGIN QUOTE -- When a key file is listed in the index file, the key file contains a cipher key that must be used to decrypt subsequent media files listed in the index file. Currently HTTP Live Streaming supports AES-128 encryption using 16-octet keys. The format of the key file is a packed array of these 16 octets in binary format. -- END QUOTE -- OK, need to look into that then. No point encrypting if you can't play back (the ultimate DRM :D) ----------------------------------------------------------------------------------------- 2017-04-26 21:17:16 btasker ----------------------------------------------------------------------------------------- Openssl doesn't seem to like the key either -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp$ openssl aes-128-cbc -d -in big_buck_bunny_720p_stereo.avi_00045.ts -out test.ts -K `cat hlstest/HLS-Stream-Creator/test7/big_buck_bunny_720p_stereo.avi.key | hexdump -e '16/1 "%02x"'` -iv `printf '%032x' 45` bad decrypt 140079633548952:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:518: -- END SNIPPET -- Something's done horribly wrong there :( OK, lets manually run an encrypt and see where we get. Will use one of the cleartext segments from the tests where encryption didn't run. Using the same key as the one above -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/encrypt_test$ ls big_buck_bunny_720p_stereo.avi_272_00001.ts in.key ben@milleniumfalcon:/tmp/encrypt_test$ INIT_VECTOR=$(printf '%032x' 1) ben@milleniumfalcon:/tmp/encrypt_test$ ENCRYPTION_KEY=$(cat in.key | hexdump -e '16/1 "%02x"') ben@milleniumfalcon:/tmp/encrypt_test$ ben@milleniumfalcon:/tmp/encrypt_test$ openssl aes-128-cbc -e -in big_buck_bunny_720p_stereo.avi_272_00001.ts -out encrypted_op.ts -nosalt -iv $INIT_VECTOR -K $ENCRYPTION_KEY ben@milleniumfalcon:/tmp/encrypt_test$ ls big_buck_bunny_720p_stereo.avi_272_00001.ts encrypted_op.ts in.key # Will it decrypt? ben@milleniumfalcon:/tmp/encrypt_test$ openssl aes-128-cbc -d -in encrypted_op.ts -out decrypted_op.ts -K $ENCRYPTION_KEY -iv $INIT_VECTOR # Seems to have done ben@milleniumfalcon:/tmp/encrypt_test$ ls -s total 1828 608 big_buck_bunny_720p_stereo.avi_272_00001.ts 608 decrypted_op.ts 608 encrypted_op.ts 4 in.key -- END SNIPPET -- Which would suggest something's going wrong in script and affecting the segments themselves, rather than specifically being an issue with the key. As a starting point, have dropped an echo into the script and set a run going to see exactly what's being run ----------------------------------------------------------------------------------------- 2017-04-26 21:23:41 btasker ----------------------------------------------------------------------------------------- Playing around while that run completes, it seems it's much simpler than it seems. If I remove the key definition from the manifest, the video plays, so the fragments aren't being encrypted. A quick check with xxd confirms -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ xxd test7/big_buck_bunny_720p_stereo.avi_00000.ts | head -n 25 00000000: 4740 1110 0042 f025 0001 c100 0000 01ff G@...B.%........ 00000010: 0001 fc80 1448 1201 0646 466d 7065 6709 .....H...FFmpeg. 00000020: 5365 7276 6963 6530 31a7 79a0 03ff ffff Service01.y..... 00000030: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000040: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000050: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000060: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000070: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000080: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000090: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000a0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000b0: ffff ffff ffff ffff ffff ffff 4740 0010 ............G@.. 000000c0: 0000 b00d 0001 c100 0000 01f0 002a b104 .............*.. 000000d0: b2ff ffff ffff ffff ffff ffff ffff ffff ................ 000000e0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 000000f0: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000100: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000110: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000120: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000130: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000140: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000150: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000160: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000170: ffff ffff ffff ffff 4750 0010 0002 b017 ........GP...... 00000180: 0001 c100 00e1 00f0 001b e100 f000 0fe1 ................ -- END SNIPPET -- There's obviously something wrong with the for loop in encrypt. The complaints about invalid length are, of course, because the data's not padded (because it's not encrypted in the first place) ----------------------------------------------------------------------------------------- 2017-04-26 21:26:12 btasker ----------------------------------------------------------------------------------------- The for statement returns empty -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ OUTPUT_DIRECTORY='test9' ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ export OUTPUT_DIRECTORY ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ for file in $(ls ${OUTPUT_DIRECTORY}/*.ts | cut -f3 -d '/'); do echo "$file"; done -- END SNIPPET -- Let's take the subcommand out of it (I don't particularly like the variable being called file either, but will fix that once I've sorted the iteration out) ----------------------------------------------------------------------------------------- 2017-04-26 21:37:58 btasker ----------------------------------------------------------------------------------------- The iterator is now finding the files, but that loops still not happy -- BEGIN SNIPPET -- test10/test10/big_buck_bunny_720p_stereo.avi_00059.ts: No such file or directory 139653670704792:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('test10/test10/big_buck_bunny_720p_stereo.avi_00059.ts','r') 139653670704792:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400: mv: cannot stat 'test10/big_buck_bunny_720p_stereo.avi_enc_59.ts': No such file or directory -- END SNIPPET -- Though the commands being run now look more or less right (aside from the input file path being incorrect) -- BEGIN SNIPPET -- Processing test10/big_buck_bunny_720p_stereo.avi_00058.ts openssl aes-128-cbc -e -in test10/test10/big_buck_bunny_720p_stereo.avi_00058.ts -out test10/big_buck_bunny_720p_stereo.avi_enc_58.ts -nosalt -iv 0000000000000000000000000000003a -K 8ed38783231164928aceb5f42f970a45 Processing test10/big_buck_bunny_720p_stereo.avi_00059.ts openssl aes-128-cbc -e -in test10/test10/big_buck_bunny_720p_stereo.avi_00059.ts -out test10/big_buck_bunny_720p_stereo.avi_enc_59.ts -nosalt -iv 0000000000000000000000000000003b -K 8ed38783231164928aceb5f42f970a45 -- END SNIPPET -- Next test run underway. I really wish I'd checked that pull more carefully, I'm not convinced this should ever have worked fully, unless you specified an absolute path for the output directory ----------------------------------------------------------------------------------------- 2017-04-26 21:43:19 btasker ----------------------------------------------------------------------------------------- OK, this is looking far more hopeful -- BEGIN SNIPPET -- ben@milleniumfalcon:/tmp/hlstest/HLS-Stream-Creator$ xxd test11/big_buck_bunny_720p_stereo.avi_00000.ts | head -n 25 00000000: 6969 bede 9aac 3913 564c 457b 42b9 6559 ii....9.VLE{B.eY 00000010: b4eb a4db 5089 a843 b0bb 09c4 7f94 6186 ....P..C......a. 00000020: 0056 9c11 6e3c 10c5 8408 bc45 22c0 c0cb .V..n<.....E"... 00000030: 01b4 b548 4e78 2c9e b36f 8452 557b cf81 ...HNx,..o.RU{.. 00000040: 2d38 06e5 8809 f27e cc89 32e5 b8bd 187c -8.....~..2....| 00000050: 7d59 49ee 2579 cb9d 0fde 9ed9 8d9b 41d5 }YI.%y........A. 00000060: 23fa fb2e 4baa c783 a8ef e8ee 5d9d 288a #...K.......].(. 00000070: e1c0 d5e0 932a c9e2 0006 ce92 7624 cf37 .....*......v$.7 00000080: b609 a817 a0e5 4239 328c dfa7 22ff 6ec4 ......B92...".n. 00000090: 6852 cd1f b784 8f20 3928 a3db 765a f912 hR..... 9(..vZ.. 000000a0: b49f 2d04 9b3c e9bb 546a 46f4 c1df 9367 ..-..<..TjF....g 000000b0: 3a3b abc1 c33b b43b c1b1 395f f067 76a6 :;...;.;..9_.gv. 000000c0: 72e6 4f71 d94e 10ae 39a8 01db 6a18 c133 r.Oq.N..9...j..3 000000d0: e7dc 2148 5b17 b823 2b80 92db 6692 c0b0 ..!H[..#+...f... 000000e0: 2f5d e226 3c51 1fb9 9afb 94ce 3fc2 399f /].&.]..(. 00000110: d6fa 6f16 d7e4 cbe3 4b06 1c0e 3435 741e ..o.....K...45t. 00000120: 7084 3000 93a5 905f 3bce 0462 98cc 5f03 p.0...._;..b.._. 00000130: c172 d286 52b3 412c f9a8 7e46 b278 85e2 .r..R.A,..~F.x.. 00000140: a22f 7f53 2e14 df63 7dbe b279 61b2 7cb7 ./.S...c}..ya.|. 00000150: 233f daf0 9682 216d 142b 44d4 9572 98a7 #?....!m.+D..r.. 00000160: 021e 2a1f c9d7 9c5b dc8c 975d 9c4f 7476 ..*....[...].Otv 00000170: b7b7 aa8b dd88 6100 841f 3e1a a4ed 334d ......a...>...3M 00000180: 915a 5c50 06d8 2b9a 9619 4313 cdad fcb4 .Z\P..+...C..... -- END SNIPPET -- VLC no longer complains about the key, and ffplay can correctly play the stream back -- BEGIN SNIPPET -- ben@milleniumfalcon:~/Documents/Notes/Home_Network$ ffplay http://scratch.holly.home/HLS/test11/big_buck_bunny_720p_stereo.avi.m3u8 -- END SNIPPET -- VLC also plays back. Will commit the fixes made so far, and fix the manifest location issue in encrypt so that this should all work with adaptive streams (as well as single bitrate streams where only one bitrate has been specified) ----------------------------------------------------------------------------------------- 2017-04-26 21:44:51 git ----------------------------------------------------------------------------------------- -- BEGIN QUOTE -- Repo: HLS-Stream-Creator Commit: a8898a33ad164abaccf9b922d050d7f0542e3879 Author: B Tasker