10

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.

aergistal
  • 29,947
  • 5
  • 70
  • 92
rickyma924
  • 172
  • 1
  • 1
  • 8

2 Answers2

22

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
aergistal
  • 29,947
  • 5
  • 70
  • 92
  • After running the command, the following error appears: Unrecognized option 'hls_key_info_file'. Error splitting the argument list: Option not found – rickyma924 Sep 23 '15 at 09:41
  • @rickyma924 you may be using an outdated version of `ffmpeg`. Build it from source or grab a [package/static build](https://ffmpeg.org/download.html). Here's a link to the `hls` documentation: https://www.ffmpeg.org/ffmpeg-formats.html#Options-2 – aergistal Sep 23 '15 at 09:43
  • @rickyma924 post the full command please, I will try it. If you installed a new `ffmpeg` make sure you're using the right one `which ffmpeg`. – aergistal Sep 23 '15 at 09:56
  • ffmpeg -i bunny.mp4 -c copy -bsf:v h264_mp4toannexb -hls_time 10 -hls_key_info_file file.keyinfo playlist.m3u8 – rickyma924 Sep 23 '15 at 09:56
  • Works for me. Do a `ffmpeg -version` and post the result. – aergistal Sep 23 '15 at 10:00
  • ffmpeg version git-2015-02-13-849ad51 Copyright (c) 2000-2015 the FFmpeg developers built with gcc 4.4.7 (GCC) 20120313 (Red Hat 4.4.7-11) Maybe the one I downloaded is a static version and cannot replace my original one – rickyma924 Sep 23 '15 at 10:01
  • @rickyma924 check the binary path with `which` to make sure you're using the correct one. – aergistal Sep 23 '15 at 10:03
  • when I use -which, it shows me ffmpeg stored in ~/bin – rickyma924 Sep 23 '15 at 10:04
  • Did you use the `git` version or the `release`. Try the `git`. – aergistal Sep 23 '15 at 10:05
  • how to make the static ffmpeg to be the default one? is it just do export static/ffmpeg/path:$PATH? – rickyma924 Sep 23 '15 at 10:05
  • I don't know where you installed it but run it from its directory, eg: `./ffmpeg -i ...` – aergistal Sep 23 '15 at 10:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90417/discussion-between-aergistal-and-rickyma924). – aergistal Sep 23 '15 at 10:13
  • Is it possible to use this technique to decrypt a live stream? – chovy Dec 14 '15 at 09:08
  • 1
    @chovy This is encryption not decryption. But yes you can both encrypt or decrypt a live AES-128 HLS stream. – aergistal Dec 14 '15 at 09:11
  • what options do i pass to ffmpeg to decrypt it? – chovy Dec 14 '15 at 09:27
  • 1
    @chovy None, you just point it to the `m3u8` and it will use the `EXT-X-KEY` information in it automatically. – aergistal Dec 14 '15 at 09:30
  • I was hoping to override the key in the playlist.m3u8 -- as I don't have control over that. – chovy Dec 14 '15 at 19:06
  • Newby question. Where do I get a key? – StormyKnight Apr 28 '17 at 02:06
  • @StormyKnight you generate one: `openssl rand 16 > $key_file`. It can be anything as long as it's 16 bytes long. – aergistal Apr 28 '17 at 15:43
  • Is it possible to achieve some sort DRM solution using this encryption method? Using ffmpeg, I'd like to be able to encrypt a stream with a user's public key so that it can only be decrypted with that user's private key but I'm not sure if this is possible. – Adam Soffer Jun 05 '18 at 03:37
  • @aergistal Thank you, very helpful example. Do I understand hls manifest KEY-URL is just a php/servlet/static file url to the raw encryption key file response. It does not do any dash-widevine/playready level PKI key exchange server things? So it's easy to have a own customized hls key delivery url entrypoint? – Whome Aug 30 '19 at 07:10
  • 1
    @Whome Yes it's just the raw key, not DRM. – aergistal Sep 02 '19 at 09:32
0

If you're using the newest (see https://trac.ffmpeg.org/ticket/10441#comment:1) version of ffmpeg, you can create an encrypted HLS stream from your video file with one single simple command:

ffmpeg -i input.mp4 -f hls -hls_enc 1 stream.m3u8

This will generate a strong (cryptographically secure pseudorandom) key, save it (in binary format) to the stream.m3u8.key file (the key file name depends on the playlist file name), encrypt all chunks (segments) using it, and add the corresponding string to the stream.m3u8 playlist file so that players can decrypt the chunks (segments) and play the video:

#EXT-X-KEY:METHOD=AES-128,URI="stream.m3u8.key"

If you already have your own key, you can use it (in hexadecimal string format) by adding -hls_enc_key option:

ffmpeg -i input.mp4 -f hls -hls_enc 1 -hls_enc_key 76a6c65c5ea762046bd749a2e632ccbb stream.m3u8

If you need to generate a strong (cryptographically secure pseudorandom) key in hexadecimal string format, you can use openssl:

openssl rand -hex 16