MPEG-DASH and ClearKey, CENC drm encryption with Nginx, bento4 and dashjs under CentOS 8

Author:

The purpose of this article is to demonstrate a simple and plain example of ClearKey DRM encryption using a DASH stream.
Usually, the ClearKey is used only for testing the encryption key and the DRM setup, because the decrypting key is transferred in a plain text to the browser. In simple DRM words, the key is transferred in plain text, and the handle of the decryption is not in some proprietary module such as CMD – Content Decryption Modules. The CMD is a proprietary module in the browsers or the players, which works like a black box when handling the decryption key. The most popular DRMs are Google’s Widevine, Apple’s Fireplay, and Microsoft PlayReady, which work through a proprietary module – CMD (Content Decryption Modules) in the browser (or the OS and player).
All the three DRMs work basically in a similar way:

  • There is a (encryption) key and a (encryption) keyID, which purpose is to identify the (encryption) key.
  • The video file is encrypted with the key and it includes the keyID.
  • The client needs to have the appropriate CMD (Content Decryption Modules) to decrypt the video.
  • The clients receive a license from a license server, which is encrypted data for the CDM on how to decrypt the video identified by the keyID. In fact, the client sends the keyID and receives the proper license (i.e. license binary data) for this keyID. That’s why keyID is included in the encrypted video. Bare in mind, the CMD is proprietary Content Decryption Module offered by the creator of the DRM – Google, Apple, Microsoft or another and it lives in the browser (OS or player). All popular browsers support at least one of the proprietary DRMs.

ClearKey is like the proprietary DRM schemes, but without the CMD (Content Decryption Modules).

The “org.w3.clearkey” Key System uses plain-text clear (unencrypted) key(s) to decrypt the source. No additional client-side content protection is required.

So, in general, there is no need for a license server when using ClearKey DRM.
Of course, an additional attempt to hide the plain-text key could be made using an extension to the client’s player such as javascript modules and etc. In general, it is perceived this approach to be less secure, because it is much easier to debug the javascript code on the client side. More on ClearKeyhttps://www.w3.org/TR/encrypted-media/#clear-key

Here are all the steps from the server till the client to use ClearKey.

STEP 1) Download and install bento4 software.

bento4 is an open source toolkit for manipulating some of the most common video formats – MP4 and DASH/HLS/CMAF media. The download page is https://www.bento4.com/downloads/ and the Linux binary for latest stable version: https://www.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-639.x86_64-unknown-linux.zip. There is also a source code snapshot link.
Download the famous blender video for the demostration: https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4
Download and unpack the binary Bento4-SDK-1-6-0-639.x86_64-unknown-linux.zip.

[root@srv ~]# dnf install -y wget unzip python39
.....
[root@srv ~]# wget https://www.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-639.x86_64-unknown-linux.zip
.....
[root@srv ~]# wget https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4
.....
[root@srv ~]# unzip Bento4-SDK-1-6-0-639.x86_64-unknown-linux.zip 
Archive:  Bento4-SDK-1-6-0-639.x86_64-unknown-linux.zip
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/aac2mp4  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp42aac  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp42avc  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp42hevc  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp42hls  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp42ts  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4compact  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4dash  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4dashclone  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4dcfpackager  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4decrypt  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4dump  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4edit  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4encrypt  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4extract  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4fragment  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4hls  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4iframeindex  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4info  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4mux  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4rtphintinfo  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4split  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4tag  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/docs/Bento4-HTML.zip  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/docs/Bento4.chm  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/docs/Bento4_SDK_documentation.doc  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/docs/Bento4_SDK_documentation.pdf  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/docs/LICENSE.txt  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap48bdlAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Ac3Parser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Ac4Parser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Ac4Utils.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AdtsParser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AesBlockCipher.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AinfAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Array.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AtomFactory.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AtomSampleTable.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AtomixAdapters.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Av1cAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AvcParser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4AvccAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4BitStream.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4BlocAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4ByteStream.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Co64Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Command.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4CommandFactory.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4CommonEncryption.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Config.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Constants.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4ContainerAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4CttsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Dac3Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Dac4Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DataBuffer.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Debug.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Dec3Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DecoderConfigDescriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DecoderSpecificInfoDescriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Descriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DescriptorFactory.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DrefAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DvccAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4DynamicCast.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Eac3Parser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4ElstAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4EsDescriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4EsdsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Expandable.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4File.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FileByteStream.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FileCopier.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FileWriter.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FragmentSampleTable.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FrmaAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4FtypAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4GrpiAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4HdlrAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4HevcParser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4HintTrackReader.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Hmac.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4HmhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4HvccAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IkmsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Interfaces.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IodsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Ipmp.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IproAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IsfmAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IsltAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4IsmaCryp.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4KeyWrap.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4LinearReader.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4List.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Marlin.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MdhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MehdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MetaData.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MfhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MfroAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MoovAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Movie.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MovieFragment.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Mp4AudioInfo.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Mpeg2Ts.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4MvhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4NalParser.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4NeptuneAdapters.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4NmhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4ObjectDescriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4OdafAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4OddaAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4OdheAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4OhdrAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4OmaDcf.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4PdinAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Piff.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Processor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Protection.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4PsshAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Results.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4RtpAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4RtpHint.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SLConfigDescriptor.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SaioAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SaizAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Sample.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SampleDescription.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SampleEntry.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SampleSource.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SampleTable.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SbgpAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SchmAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SdpAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SegmentBuilder.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SencAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SgpdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SidxAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SmhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StcoAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SthdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StreamCipher.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4String.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StscAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StsdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StssAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4StszAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SttsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Stz2Atom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4SyntheticSampleTable.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TencAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TfdtAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TfhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TfraAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TimsAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TkhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Track.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TrakAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TrefTypeAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TrexAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4TrunAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Types.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4UrlAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Utils.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4UuidAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4Version.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4VmhdAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Ap4VpccAtom.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/include/Bento4C.h  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/lib/libap4.a  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/aes.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/check-indexes.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/mp4-dash-clone.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/mp4-dash-encode.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/mp4-dash.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/mp4-hls.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/mp4utils.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/pr-derive-key.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/skm.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/subtitles.py  
  inflating: Bento4-SDK-1-6-0-639.x86_64-unknown-linux/utils/wv-request.py

STEP 2) Encrypt the video with CENC encryption and turn it into DASH fragments.

First, fragment the video:

[root@srv ~]# Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4fragment bbb_sunflower_1080p_30fps_normal.mp4 bbb_sunflower_1080p_30fps_normal-fragmented.mp4
found regular I-frame interval: 9647 frames (at 30.000 frames per second)
auto-detected fragment duration too large, using default

Generate the key and the keyID, then convert them to HEX:

[root@srv ~]# head -c16 </dev/urandom > encrytion.key
[root@srv ~]# ls -l encrytion.key 
-rw-r--r--. 1 root root 16 Apr 22 14:39 encrytion.key
[root@srv ~]# cat encrytion.key|hexdump
0000000 26ed 806e d20f 8ced 9368 a9e0 191f 59da
0000010
[root@srv ~]# cat encrytion.key | hexdump -v -e '/1 "%02X"'
ED266E800FD2ED8C6893E0A91F19DA59

The HEX string of the encryption key is ED266E800FD2ED8C6893E0A91F19DA59.
The same procedure for the keyID:

[root@srv ~]# head -c16 </dev/urandom > encrytion.keyID
[root@srv ~]# cat encrytion.keyID | hexdump -v -e '/1 "%02X"'
4DC2C4DE5CB2103ECD807347E96D29EA

The keyID is 4DC2C4DE5CB2103ECD807347E96D29EA.
Using mp4dash to generate the MPEG-DASH format of the video. The mp4dash format below is keyID:key:salt and the files will be written in the folder with the name “output”:

[root@srv ~]# Bento4-SDK-1-6-0-639.x86_64-unknown-linux/bin/mp4dash -v --clearkey --encryption-key=4DC2C4DE5CB2103ECD807347E96D29EA:ED266E800FD2ED8C6893E0A91F19DA59:random --use-segment-timeline -o output bbb_sunflower_1080p_30fps_normal-fragmented.mp4
Profiles: urn:mpeg:dash:profile:isoff-live:2011
Encrypting track IDs [1, 2, 3] in bbb_sunflower_1080p_30fps_normal-fragmented.mp4
ERROR: failed to process the file (-10)
Parsing media file 1: tmp3o7dcs__ = Encrypted[bbb_sunflower_1080p_30fps_normal-fragmented.mp4]
Audio: {('audio', 'und', 'mp4a.6B'): [File 1#2], ('audio', 'und', 'ac-3'): [File 1#3]}
Video: {('video', 'avc1'): [File 1#1]}
Subtitles: {}
Key info for File 1#2: [KID=4DC2C4DE5CB2103ECD807347E96D29EA, KEY=ED266E800FD2ED8C6893E0A91F19DA59]
Key info for File 1#3: [KID=4DC2C4DE5CB2103ECD807347E96D29EA, KEY=ED266E800FD2ED8C6893E0A91F19DA59]
Key info for File 1#1: [KID=4DC2C4DE5CB2103ECD807347E96D29EA, KEY=ED266E800FD2ED8C6893E0A91F19DA59]
INFO: adjusting segment duration for audio track File 1#2 to 4.535588972431079 to match the video
INFO: adjusting segment duration for audio track File 1#3 to 4.535588972431079 to match the video
audio track: File 1#2 - language=und, max bitrate=167886, avg bitrate=166947, req bandwidth=166821, codec=mp4a.6B
audio track: File 1#3 - language=und, max bitrate=326183, avg bitrate=325281, req bandwidth=325154, codec=ac-3
video track: File 1#1 - language=und, max bitrate=18087465, avg bitrate=3055359, req bandwidth=5926971, codec=avc1.640029
Splitting media file (audio) tmp3o7dcs__ = Encrypted[bbb_sunflower_1080p_30fps_normal-fragmented.mp4]
Splitting media file (audio) tmp3o7dcs__ = Encrypted[bbb_sunflower_1080p_30fps_normal-fragmented.mp4]
Splitting media file (video) tmp3o7dcs__ = Encrypted[bbb_sunflower_1080p_30fps_normal-fragmented.mp4]
[root@srv ~]# ls -altr output/
total 32
dr-xr-x---. 4 root root  4096 Apr 24 20:06 ..
drwxr-xr-x. 3 root root  4096 Apr 24 20:06 audio
drwxr-xr-x. 3 root root  4096 Apr 24 20:06 video
-rw-r--r--. 1 root root 12573 Apr 24 20:06 stream.mpd
drwxr-xr-x. 4 root root  4096 Apr 24 20:06 .
[root@srv ~]# find output/
output/
output/video
output/video/avc1
output/video/avc1/seg-81.m4s
output/video/avc1/seg-97.m4sopens
output/video/avc1/seg-108.m4s
output/video/avc1/seg-9.m4s
output/video/avc1/seg-33.m4s
output/video/avc1/seg-36.m4s
output/video/avc1/seg-75.m4s
output/video/avc1/seg-50.m4s
output/video/avc1/seg-111.m4s
output/video/avc1/seg-100.m4s
output/video/avc1/seg-82.m4s
output/video/avc1/seg-10.m4s
output/video/avc1/seg-107.m4s
output/video/avc1/seg-94.m4s
output/video/avc1/seg-4.m4s
output/video/avc1/seg-45.m4s
output/video/avc1/seg-63.m4s
output/video/avc1/seg-95.m4s
output/video/avc1/seg-115.m4s
output/video/avc1/seg-41.m4s
output/video/avc1/seg-54.m4s
output/video/avc1/seg-105.m4s
output/video/avc1/seg-56.m4s
output/video/avc1/seg-78.m4s
output/video/avc1/seg-6.m4s
output/video/avc1/seg-135.m4s
output/video/avc1/seg-58.m4s
output/video/avc1/seg-126.m4s
output/video/avc1/seg-57.m4s
output/video/avc1/seg-133.m4s
output/video/avc1/seg-112.m4s
output/video/avc1/seg-12.m4s
output/video/avc1/seg-61.m4s
output/video/avc1/seg-52.m4s
output/video/avc1/seg-43.m4s
output/video/avc1/seg-84.m4s
output/video/avc1/seg-74.m4s
output/video/avc1/seg-76.m4s
output/video/avc1/seg-39.m4s
output/video/avc1/seg-113.m4s
output/video/avc1/seg-18.m4s
output/video/avc1/seg-129.m4s
output/video/avc1/seg-48.m4s
output/video/avc1/seg-80.m4s
output/video/avc1/seg-132.m4s
output/video/avc1/seg-122.m4s
output/video/avc1/seg-91.m4s
output/video/avc1/seg-134.m4s
output/video/avc1/seg-127.m4s
output/video/avc1/seg-123.m4s
output/video/avc1/seg-118.m4s
output/video/avc1/seg-62.m4s
output/video/avc1/seg-102.m4s
output/video/avc1/seg-86.m4s
output/video/avc1/seg-93.m4s
output/video/avc1/seg-114.m4s
output/video/avc1/seg-44.m4s
output/video/avc1/seg-88.m4s
output/video/avc1/seg-2.m4s
output/video/avc1/seg-101.m4s
output/video/avc1/seg-53.m4s
output/video/avc1/seg-103.m4s
output/video/avc1/seg-1.m4s
output/video/avc1/seg-92.m4s
output/video/avc1/seg-25.m4s
output/video/avc1/seg-96.m4s
output/video/avc1/seg-38.m4s
output/video/avc1/seg-55.m4s
output/video/avc1/seg-121.m4s
output/video/avc1/init.mp4
output/video/avc1/seg-65.m4s
output/video/avc1/seg-17.m4s
output/video/avc1/seg-59.m4s
output/video/avc1/seg-83.m4s
output/video/avc1/seg-106.m4s
output/video/avc1/seg-64.m4s
output/video/avc1/seg-40.m4s
output/video/avc1/seg-8.m4s
output/video/avc1/seg-130.m4s
output/video/avc1/seg-109.m4s
output/video/avc1/seg-28.m4s
output/video/avc1/seg-70.m4s
output/video/avc1/seg-87.m4s
output/video/avc1/seg-49.m4s
output/video/avc1/seg-116.m4s
output/video/avc1/seg-72.m4s
output/video/avc1/seg-7.m4s
output/video/avc1/seg-77.m4s
output/video/avc1/seg-67.m4s
output/video/avc1/seg-119.m4s
output/video/avc1/seg-27.m4s
output/video/avc1/seg-15.m4s
output/video/avc1/seg-131.m4s
output/video/avc1/seg-120.m4s
output/video/avc1/seg-124.m4s
output/video/avc1/seg-98.m4s
output/video/avc1/seg-85.m4s
output/video/avc1/seg-47.m4s
output/video/avc1/seg-11.m4s
output/video/avc1/seg-99.m4s
output/video/avc1/seg-79.m4s
output/video/avc1/seg-125.m4s
output/video/avc1/seg-20.m4s
output/video/avc1/seg-90.m4s
output/video/avc1/seg-128.m4s
output/video/avc1/seg-30.m4s
output/video/avc1/seg-46.m4s
output/video/avc1/seg-66.m4s
output/video/avc1/seg-42.m4s
output/video/avc1/seg-21.m4s
output/video/avc1/seg-71.m4s
output/video/avc1/seg-19.m4s
output/video/avc1/seg-16.m4s
output/video/avc1/seg-51.m4s
output/video/avc1/seg-14.m4s
output/video/avc1/seg-23.m4s
output/video/avc1/seg-117.m4s
output/video/avc1/seg-68.m4s
output/video/avc1/seg-73.m4s
output/video/avc1/seg-5.m4s
output/video/avc1/seg-3.m4s
output/video/avc1/seg-60.m4s
output/video/avc1/seg-110.m4s
output/video/avc1/seg-31.m4s
output/video/avc1/seg-13.m4s
output/video/avc1/seg-26.m4s
output/video/avc1/seg-35.m4s
output/video/avc1/seg-22.m4s
output/video/avc1/seg-89.m4s
output/video/avc1/seg-32.m4s
output/video/avc1/seg-104.m4s
output/video/avc1/seg-29.m4s
output/video/avc1/seg-24.m4s
output/video/avc1/seg-34.m4s
output/video/avc1/seg-37.m4s
output/video/avc1/seg-69.m4s
output/stream.mpd
output/audio
output/audio/und
output/audio/und/ac-3
output/audio/und/ac-3/seg-81.m4s
output/audio/und/ac-3/seg-97.m4s
output/audio/und/ac-3/seg-108.m4s
output/audio/und/ac-3/seg-9.m4s
output/audio/und/ac-3/seg-33.m4s
output/audio/und/ac-3/seg-36.m4s
output/audio/und/ac-3/seg-75.m4s
output/audio/und/ac-3/seg-50.m4s
output/audio/und/ac-3/seg-111.m4s
output/audio/und/ac-3/seg-100.m4s
output/audio/und/ac-3/seg-82.m4s
output/audio/und/ac-3/seg-10.m4s
output/audio/und/ac-3/seg-107.m4s
output/audio/und/ac-3/seg-94.m4s
output/audio/und/ac-3/seg-4.m4s
output/audio/und/ac-3/seg-45.m4s
output/audio/und/ac-3/seg-63.m4s
output/audio/und/ac-3/seg-95.m4s
output/audio/und/ac-3/seg-115.m4s
output/audio/und/ac-3/seg-41.m4s
output/audio/und/ac-3/seg-54.m4s
output/audio/und/ac-3/seg-105.m4s
output/audio/und/ac-3/seg-56.m4s
output/audio/und/ac-3/seg-78.m4s
output/audio/und/ac-3/seg-6.m4s
output/audio/und/ac-3/seg-135.m4s
output/audio/und/ac-3/seg-58.m4s
output/audio/und/ac-3/seg-126.m4s
output/audio/und/ac-3/seg-57.m4s
output/audio/und/ac-3/seg-133.m4s
output/audio/und/ac-3/seg-112.m4s
output/audio/und/ac-3/seg-12.m4s
output/audio/und/ac-3/seg-61.m4s
output/audio/und/ac-3/seg-52.m4s
output/audio/und/ac-3/seg-43.m4s
output/audio/und/ac-3/seg-84.m4s
output/audio/und/ac-3/seg-74.m4s
output/audio/und/ac-3/seg-76.m4s
output/audio/und/ac-3/seg-39.m4s
output/audio/und/ac-3/seg-113.m4s
output/audio/und/ac-3/seg-18.m4s
output/audio/und/ac-3/seg-129.m4s
output/audio/und/ac-3/seg-48.m4s
output/audio/und/ac-3/seg-80.m4s
output/audio/und/ac-3/seg-132.m4s
output/audio/und/ac-3/seg-122.m4s
output/audio/und/ac-3/seg-91.m4s
output/audio/und/ac-3/seg-134.m4s
output/audio/und/ac-3/seg-127.m4s
output/audio/und/ac-3/seg-123.m4s
output/audio/und/ac-3/seg-118.m4s
output/audio/und/ac-3/seg-62.m4s
output/audio/und/ac-3/seg-102.m4s
output/audio/und/ac-3/seg-86.m4s
output/audio/und/ac-3/seg-93.m4s
output/audio/und/ac-3/seg-114.m4s
output/audio/und/ac-3/seg-44.m4s
output/audio/und/ac-3/seg-88.m4s
output/audio/und/ac-3/seg-2.m4s
output/audio/und/ac-3/seg-101.m4s
output/audio/und/ac-3/seg-53.m4s
output/audio/und/ac-3/seg-103.m4s
output/audio/und/ac-3/seg-1.m4s
output/audio/und/ac-3/seg-92.m4s
output/audio/und/ac-3/seg-25.m4s
output/audio/und/ac-3/seg-96.m4s
output/audio/und/ac-3/seg-38.m4s
output/audio/und/ac-3/seg-55.m4s
output/audio/und/ac-3/seg-121.m4s
output/audio/und/ac-3/init.mp4
output/audio/und/ac-3/seg-65.m4s
output/audio/und/ac-3/seg-17.m4s
output/audio/und/ac-3/seg-59.m4s
output/audio/und/ac-3/seg-83.m4s
output/audio/und/ac-3/seg-106.m4s
output/audio/und/ac-3/seg-64.m4s
output/audio/und/ac-3/seg-40.m4s
output/audio/und/ac-3/seg-8.m4s
output/audio/und/ac-3/seg-130.m4s
output/audio/und/ac-3/seg-109.m4s
output/audio/und/ac-3/seg-28.m4s
output/audio/und/ac-3/seg-70.m4s
output/audio/und/ac-3/seg-87.m4s
output/audio/und/ac-3/seg-49.m4s
output/audio/und/ac-3/seg-116.m4s
output/audio/und/ac-3/seg-72.m4s
output/audio/und/ac-3/seg-7.m4s
output/audio/und/ac-3/seg-77.m4s
output/audio/und/ac-3/seg-67.m4s
output/audio/und/ac-3/seg-119.m4s
output/audio/und/ac-3/seg-27.m4s
output/audio/und/ac-3/seg-15.m4s
output/audio/und/ac-3/seg-131.m4s
output/audio/und/ac-3/seg-120.m4s
output/audio/und/ac-3/seg-124.m4s
output/audio/und/ac-3/seg-98.m4s
output/audio/und/ac-3/seg-85.m4s
output/audio/und/ac-3/seg-47.m4s
output/audio/und/ac-3/seg-11.m4s
output/audio/und/ac-3/seg-99.m4s
output/audio/und/ac-3/seg-79.m4s
output/audio/und/ac-3/seg-125.m4s
output/audio/und/ac-3/seg-20.m4s
output/audio/und/ac-3/seg-90.m4s
output/audio/und/ac-3/seg-128.m4s
output/audio/und/ac-3/seg-30.m4s
output/audio/und/ac-3/seg-46.m4s
output/audio/und/ac-3/seg-66.m4s
output/audio/und/ac-3/seg-42.m4s
output/audio/und/ac-3/seg-21.m4s
output/audio/und/ac-3/seg-71.m4s
output/audio/und/ac-3/seg-19.m4s
output/audio/und/ac-3/seg-16.m4s
output/audio/und/ac-3/seg-51.m4s
output/audio/und/ac-3/seg-14.m4s
output/audio/und/ac-3/seg-23.m4s
output/audio/und/ac-3/seg-117.m4s
output/audio/und/ac-3/seg-68.m4s
output/audio/und/ac-3/seg-73.m4s
output/audio/und/ac-3/seg-5.m4s
output/audio/und/ac-3/seg-3.m4s
output/audio/und/ac-3/seg-60.m4s
output/audio/und/ac-3/seg-110.m4s
output/audio/und/ac-3/seg-31.m4s
output/audio/und/ac-3/seg-13.m4s
output/audio/und/ac-3/seg-26.m4s
output/audio/und/ac-3/seg-35.m4s
output/audio/und/ac-3/seg-22.m4s
output/audio/und/ac-3/seg-89.m4s
output/audio/und/ac-3/seg-32.m4s
output/audio/und/ac-3/seg-104.m4s
output/audio/und/ac-3/seg-29.m4s
output/audio/und/ac-3/seg-24.m4s
output/audio/und/ac-3/seg-34.m4s
output/audio/und/ac-3/seg-37.m4s
output/audio/und/ac-3/seg-69.m4s
output/audio/und/mp4a.6B
output/audio/und/mp4a.6B/seg-81.m4s
output/audio/und/mp4a.6B/seg-97.m4s
output/audio/und/mp4a.6B/seg-108.m4s
output/audio/und/mp4a.6B/seg-9.m4s
output/audio/und/mp4a.6B/seg-33.m4s
output/audio/und/mp4a.6B/seg-36.m4s
output/audio/und/mp4a.6B/seg-75.m4s
output/audio/und/mp4a.6B/seg-50.m4s
output/audio/und/mp4a.6B/seg-111.m4s
output/audio/und/mp4a.6B/seg-100.m4s
output/audio/und/mp4a.6B/seg-82.m4s
output/audio/und/mp4a.6B/seg-10.m4s
output/audio/und/mp4a.6B/seg-107.m4s
output/audio/und/mp4a.6B/seg-94.m4s
output/audio/und/mp4a.6B/seg-4.m4s
output/audio/und/mp4a.6B/seg-45.m4s
output/audio/und/mp4a.6B/seg-63.m4s
output/audio/und/mp4a.6B/seg-95.m4s
output/audio/und/mp4a.6B/seg-115.m4s
output/audio/und/mp4a.6B/seg-41.m4s
output/audio/und/mp4a.6B/seg-54.m4s
output/audio/und/mp4a.6B/seg-105.m4s
output/audio/und/mp4a.6B/seg-56.m4s
output/audio/und/mp4a.6B/seg-78.m4s
output/audio/und/mp4a.6B/seg-6.m4s
output/audio/und/mp4a.6B/seg-135.m4s
output/audio/und/mp4a.6B/seg-58.m4s
output/audio/und/mp4a.6B/seg-126.m4s
output/audio/und/mp4a.6B/seg-57.m4s
output/audio/und/mp4a.6B/seg-133.m4s
output/audio/und/mp4a.6B/seg-112.m4s
output/audio/und/mp4a.6B/seg-12.m4s
output/audio/und/mp4a.6B/seg-61.m4s
output/audio/und/mp4a.6B/seg-52.m4s
output/audio/und/mp4a.6B/seg-43.m4s
output/audio/und/mp4a.6B/seg-84.m4s
output/audio/und/mp4a.6B/seg-74.m4s
output/audio/und/mp4a.6B/seg-76.m4s
output/audio/und/mp4a.6B/seg-39.m4s
output/audio/und/mp4a.6B/seg-113.m4s
output/audio/und/mp4a.6B/seg-18.m4s
output/audio/und/mp4a.6B/seg-129.m4s
output/audio/und/mp4a.6B/seg-48.m4s
output/audio/und/mp4a.6B/seg-80.m4s
output/audio/und/mp4a.6B/seg-132.m4s
output/audio/und/mp4a.6B/seg-122.m4s
output/audio/und/mp4a.6B/seg-91.m4s
output/audio/und/mp4a.6B/seg-134.m4s
output/audio/und/mp4a.6B/seg-127.m4s
output/audio/und/mp4a.6B/seg-123.m4s
output/audio/und/mp4a.6B/seg-118.m4s
output/audio/und/mp4a.6B/seg-62.m4s
output/audio/und/mp4a.6B/seg-102.m4s
output/audio/und/mp4a.6B/seg-86.m4s
output/audio/und/mp4a.6B/seg-93.m4s
output/audio/und/mp4a.6B/seg-114.m4s
output/audio/und/mp4a.6B/seg-44.m4s
output/audio/und/mp4a.6B/seg-88.m4s
output/audio/und/mp4a.6B/seg-2.m4s
output/audio/und/mp4a.6B/seg-101.m4s
output/audio/und/mp4a.6B/seg-53.m4s
output/audio/und/mp4a.6B/seg-103.m4s
output/audio/und/mp4a.6B/seg-1.m4s
output/audio/und/mp4a.6B/seg-92.m4s
output/audio/und/mp4a.6B/seg-25.m4s
output/audio/und/mp4a.6B/seg-96.m4s
output/audio/und/mp4a.6B/seg-38.m4s
output/audio/und/mp4a.6B/seg-55.m4s
output/audio/und/mp4a.6B/seg-121.m4s
output/audio/und/mp4a.6B/init.mp4
output/audio/und/mp4a.6B/seg-65.m4s
output/audio/und/mp4a.6B/seg-17.m4s
output/audio/und/mp4a.6B/seg-59.m4s
output/audio/und/mp4a.6B/seg-83.m4s
output/audio/und/mp4a.6B/seg-106.m4s
output/audio/und/mp4a.6B/seg-64.m4s
output/audio/und/mp4a.6B/seg-40.m4s
output/audio/und/mp4a.6B/seg-8.m4s
output/audio/und/mp4a.6B/seg-130.m4s
output/audio/und/mp4a.6B/seg-109.m4s
output/audio/und/mp4a.6B/seg-28.m4s
output/audio/und/mp4a.6B/seg-70.m4s
output/audio/und/mp4a.6B/seg-87.m4s
output/audio/und/mp4a.6B/seg-49.m4s
output/audio/und/mp4a.6B/seg-116.m4s
output/audio/und/mp4a.6B/seg-72.m4s
output/audio/und/mp4a.6B/seg-7.m4s
output/audio/und/mp4a.6B/seg-77.m4s
output/audio/und/mp4a.6B/seg-67.m4s
output/audio/und/mp4a.6B/seg-119.m4s
output/audio/und/mp4a.6B/seg-27.m4s
output/audio/und/mp4a.6B/seg-15.m4s
output/audio/und/mp4a.6B/seg-131.m4s
output/audio/und/mp4a.6B/seg-120.m4s
output/audio/und/mp4a.6B/seg-124.m4s
output/audio/und/mp4a.6B/seg-98.m4s
output/audio/und/mp4a.6B/seg-85.m4s
output/audio/und/mp4a.6B/seg-47.m4s
output/audio/und/mp4a.6B/seg-11.m4s
output/audio/und/mp4a.6B/seg-99.m4s
output/audio/und/mp4a.6B/seg-79.m4s
output/audio/und/mp4a.6B/seg-125.m4s
output/audio/und/mp4a.6B/seg-20.m4s
output/audio/und/mp4a.6B/seg-90.m4s
output/audio/und/mp4a.6B/seg-128.m4s
output/audio/und/mp4a.6B/seg-30.m4s
output/audio/und/mp4a.6B/seg-46.m4s
output/audio/und/mp4a.6B/seg-66.m4s
output/audio/und/mp4a.6B/seg-42.m4s
output/audio/und/mp4a.6B/seg-21.m4s
output/audio/und/mp4a.6B/seg-71.m4s
output/audio/und/mp4a.6B/seg-19.m4s
output/audio/und/mp4a.6B/seg-16.m4s
output/audio/und/mp4a.6B/seg-51.m4s
output/audio/und/mp4a.6B/seg-14.m4s
output/audio/und/mp4a.6B/seg-23.m4s
output/audio/und/mp4a.6B/seg-117.m4s
output/audio/und/mp4a.6B/seg-68.m4s
output/audio/und/mp4a.6B/seg-73.m4s
output/audio/und/mp4a.6B/seg-5.m4s
output/audio/und/mp4a.6B/seg-3.m4s
output/audio/und/mp4a.6B/seg-60.m4s
output/audio/und/mp4a.6B/seg-110.m4s
output/audio/und/mp4a.6B/seg-31.m4s
output/audio/und/mp4a.6B/seg-13.m4s
output/audio/und/mp4a.6B/seg-26.m4s
output/audio/und/mp4a.6B/seg-35.m4s
output/audio/und/mp4a.6B/seg-22.m4s
output/audio/und/mp4a.6B/seg-89.m4s
output/audio/und/mp4a.6B/seg-32.m4s
output/audio/und/mp4a.6B/seg-104.m4s
output/audio/und/mp4a.6B/seg-29.m4s
output/audio/und/mp4a.6B/seg-24.m4s
output/audio/und/mp4a.6B/seg-34.m4s
output/audio/und/mp4a.6B/seg-37.m4s
output/audio/und/mp4a.6B/seg-69.m4s

Using the option –clearkey will put the ClearKey signature in the playlist file stream.mpd, which will allow using ONLY keys in the dashjs configuration without using a license URL.

<ContentProtection schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e" value="ClearKey1.0"/>

And the dashjs player will work without license URL with the following configuration:

        const protData = {
                "org.w3.clearkey": {
                        "clearkeys": {
                            "TcLE3lyyED7NgHNH6W0p6g" : "7SZugA/S7Yxok+CpHxnaWQ"
                        },
                        "priority": 0
                }
        };

There is a whole web page with all the HTML and javascript code in STEP 4).

STEP 3) Install and configure the webserver Nginx.

Install the webserver, in this case, Nginx, and then configure it. There is an additional step to generate a self-signed certificate for the domain, which is going to serve the MPEG-DASH video file and the HTML player.
Installing the Nginx webserver. The dnf output of installing the Nginx is skipped here.

[root@srv ~]# dnf install -y nginx
.....
.....
[root@srv ~]# mkdir -p /etc/ssl/nginx
[root@srv ~]# openssl genrsa -out /etc/ssl/nginx/example.com.key 2048 
Generating RSA private key, 2048 bit long modulus (2 primes)
...........................................................................................+++++
..........................................................................+++++
e is 65537 (0x010001)
[root@srv ~]# openssl req -new -key /etc/ssl/nginx/example.com.key -out /etc/ssl/nginx/example.com.csr -subj '/C=us/ST=newyork/L=newyork/O=mygroup/OU=servicing/CN=example.com/emailAddress=admin@example.com'
[root@srv ~]# openssl x509 -req -days 3650 -in /etc/ssl/nginx/example.com.csr -signkey /etc/ssl/nginx/example.com.key -out /etc/ssl/nginx/example.com.crt
Signature ok
subject=C = us, ST = newyork, L = newyork, O = mygroup, OU = servicing, CN = example.com, emailAddress = admin@example.com
Getting Private key
[root@srv ~]# chmod 400 /etc/ssl/nginx/example.com.*

The simple Nginx configuration for SSL. Add the following configuration to the /etc/nginx/nginx.conf at the end of the file before the last “}”.

    server {
        listen       443 ssl http2 default_server;
        listen       [::]:443 ssl http2 default_server;
        server_name  example.com;
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/ssl/nginx/example.com.crt";
        ssl_certificate_key "/etc/ssl/nginx/example.com.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;

        add_header 'Access-Control-Allow-Headers' 'origin,range,accept-encoding,referer';
        add_header 'Access-Control-Expose-Headers' 'Server,range,Content-Length,Content-Range,Date';
        add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS';
        add_header 'Access-Control-Allow-Origin' '*';
    }

Start the Nginx web server and configure the firewall to allow all HTTP/HTTPS traffic.

[root@srv ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@srv ~]# systemctl start nginx
[root@srv ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2022-04-25 14:33:20 UTC; 2min 36s ago
  Process: 4521 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 4519 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 4517 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 4522 (nginx)
    Tasks: 3 (limit: 11381)
   Memory: 5.0M
   CGroup: /system.slice/nginx.service
           ├─4522 nginx: master process /usr/sbin/nginx
           ├─4523 nginx: worker process
           └─4524 nginx: worker process

Apr 25 14:33:20 srv systemd[1]: Starting The nginx HTTP and reverse proxy server...
Apr 25 14:33:20 srv nginx[4519]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Apr 25 14:33:20 srv nginx[4519]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Apr 25 14:33:20 srv systemd[1]: Started The nginx HTTP and reverse proxy server.
[root@srv ~]# firewall-cmd --permanent --zone=public --add-service=http
success
[root@srv ~]# firewall-cmd --permanent --zone=public --add-service=https
success
[root@srv ~]# firewall-cmd --reload
success
[root@srv ~]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3
  sources: 
  services: cockpit dhcpv6-client http https ssh
  ports: 
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

Point the example.com to the IP of the Nginx webserver:

echo "192.168.0.20    example.com" >> /etc/hosts

For example, if local IP is used.

STEP 4) Simple dashjs player page.

Sample page with dashjs player in /usr/share/nginx/html/player-dashjs.html.

<!DOCTYPE html>
<html>
  <head>
    <title>MPEG-DASH</title>
    <!-- DASH reference implementation -->
    <script src="https://cdn.dashjs.org/latest/dash.all.debug.js"></script>

<script>
    function init() {
        const protData = {
                "org.w3.clearkey": {
                        "clearkeys": {
                            "TcLE3lyyED7NgHNH6W0p6g" : "7SZugA/S7Yxok+CpHxnaWQ"
                        },
                        "priority": 0
                }
        };
        var video,
            player,
            url = "https://example.com/output/stream.mpd";

        video = document.querySelector("video");
        player = dashjs.MediaPlayer().create();
        player.updateSettings({ 'debug': { 'logLevel': dashjs.Debug.LOG_LEVEL_DEBUG }});
        
        player.initialize(video, url, true);
        player.setProtectionData(protData);
        
    }
    function check() {
        if (location.protocol === 'http:' && location.hostname !== 'localhost') {
            var out = 'This page has been loaded under http. This might result in the EME APIs not being available to the player and any DRM-protected content will fail to play. ' +
                'If you wish to test manifest URLs that require EME support, then <a href=\'https:' + window.location.href.substring(window.location.protocol.length) + '\'>reload this page under https</a>.'
            var div = document.getElementById('http-warning');
            div.innerHTML = out;
            div.style.display = ''
        }
    }
</script>
  </head>
  <body onload="init()">
    <video id="html5video" width="80%" height="80%" controls>
    </video>
  </body>
</html>

The player expect the base64 of encryption key and encryption keyID, so use Linux base64 command. Move the encrypted video to the webserver root directory.

[root@srv ~]# cat encrytion.key|base64
[root@srv ~]# 7SZugA/S7Yxok+CpHxnaWQ==
[root@srv ~]# cat encrytion.keyID|base64
[root@srv ~]# TcLE3lyyED7NgHNH6W0p6g==
[root@srv ~]# mv output /usr/share/nginx/html/
[root@srv ~]# restorecon -R /usr/share/nginx/html/

Now, load the Firefox/Chrome browser https://example.com/player-dashjs.html, accept and continue with the warning of the unsecured page, because of the self-issued certificated, and play the video.

SCREENSHOT 1) The ClearKey is handled by the application, so no need for an additional license URL.

main menu
Play ClearKey DRM handled by application

SCREENSHOT 2) The segments are downloaded, decrypted with the encryption key and played successfully.

main menu
segments download

Bonus – all javascript console output

Here is the Firefox javascript console output of a successful played ClearKey encrypted video:

GEThttps://example.com/favicon.ico
[HTTP/2 404 Not Found 0ms]

[2] Stopping the gap controller dash.all.debug.js:18001:19
[9][Protection] EME detected on this user agent! (ProtectionModel_21Jan2015) dash.all.debug.js:18001:19
[9][MediaPlayer] Streaming Initialized dash.all.debug.js:18001:19
[12][EventController] Start Event Controller dash.all.debug.js:18001:19
[17][MediaPlayer] Playback Initialized dash.all.debug.js:18001:19
[18][MediaPlayer] [dash.js 4.3.0] MediaPlayer has been initialized dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/stream.mpd
[HTTP/2 304 Not Modified 4ms]

[259][DashParser] Parsing complete: ( xml2json: 43.0ms, objectiron: 0.00ms, total: 0.0430s) dash.all.debug.js:18001:19
[261][StreamController] Manifest updated... updating data system wide. dash.all.debug.js:18001:19
[263][ManifestUpdater] Manifest has been refreshed at Mon Apr 25 2022 21:44:29 GMT+0300 (Eastern European Summer Time)[1650912269.891]  dash.all.debug.js:18001:19
[263][CapabilitiesFilter] [Stream] Codec audio/mp4;codecs="mp4a.6B" not supported  dash.all.debug.js:18001:19
[264][CapabilitiesFilter] [Stream] Codec audio/mp4;codecs="ac-3" not supported  dash.all.debug.js:18001:19
[264][CapabilitiesFilter] AdaptationSet has been removed because of no supported Representation dash.all.debug.js:18001:19
[265][CapabilitiesFilter] AdaptationSet has been removed because of no supported Representation dash.all.debug.js:18001:19
[268][GapController] Starting the gap controller dash.all.debug.js:18001:19
[270][StreamController] Switch to stream defaultId_0. Seektime is 0, current playback time is null. Seamless period switch is set to false dash.all.debug.js:18001:19
[272][StreamController] MediaSource attached to element.  Waiting on open... dash.all.debug.js:18001:19
[277][StreamController] MediaSource is open! dash.all.debug.js:18001:19
[278][MediaSourceController] Set MediaSource duration:618.7 dash.all.debug.js:18001:19
[283][Stream] No audio data. dash.all.debug.js:18001:19
[287][Stream] No text data. dash.all.debug.js:18001:19
[288][Stream] No muxed data. dash.all.debug.js:18001:19
[289][Stream] No image data. dash.all.debug.js:18001:19
[293][SourceBufferSink][video] Updated append window for video. Set start to 0 and end to 618.71 dash.all.debug.js:18001:19
[298][ProtectionModel_21Jan2015] Requesting key system access for system string org.w3.clearkey dash.all.debug.js:18001:19
[299][ProtectionController] DRM: KeySystem Access Granted for system string (org.w3.clearkey)!  Selecting key system... dash.all.debug.js:18001:19
[302][ScheduleController][video] Quality has changed, get init request for representationid = video/avc1 dash.all.debug.js:18001:19
[314][ProtectionModel_21Jan2015] DRM: Session created.  SessionID = 3 dash.all.debug.js:18001:19
[316][ProtectionController] DRM: onKeyMessage dash.all.debug.js:18001:19
[317][ProtectionController] DRM: ClearKey license request handled by application! dash.all.debug.js:18001:19
[320][ProtectionController] DRM: key status = usable dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/init.mp4
[HTTP/2 304 Not Modified 1ms]

[418][BufferController][video] Append Init fragment video  with representationId: video/avc1  and quality: 0 , data size: 790 dash.all.debug.js:18001:19
[419][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/init.mp4  dash.all.debug.js:18001:19
Autoplay is only allowed when approved by the user, the site is activated by the user, or media is muted. dash.all.debug.js:49901:22
[421][VideoModel] Caught pending play exception - continuing (NotAllowedError: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.) dash.all.debug.js:18001:19
[422][PlaybackController] Native video element event: loadedmetadata dash.all.debug.js:18001:19
[426][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[427][ScheduleController][video] [video] lastInitializedRepresentationInfo changed to 0 dash.all.debug.js:18001:19
[428][ScheduleController][video] Top quality video index has changed from NaN to 0 dash.all.debug.js:18001:19
[428][ScheduleController][video] Media segment needed for video and stream id defaultId_0 dash.all.debug.js:18001:19
[431][DashHandler][video] Index for time 0 is 0 dash.all.debug.js:18001:19
[432][StreamProcessor][video] Next fragment request url for stream id defaultId_0 and media type video is https://example.com/output/video/avc1/seg-1.m4s dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/seg-1.m4s
[HTTP/2 304 Not Modified 1ms]

[647][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/seg-1.m4s  dash.all.debug.js:18001:19
[651][BufferController][video] Got enough buffer to start dash.all.debug.js:18001:19
[653][BufferController][video] Buffered range: 0 - 8.333333, currentTime =  0 dash.all.debug.js:18001:19
[655][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[658][ScheduleController][video] Media segment needed for video and stream id defaultId_0 dash.all.debug.js:18001:19
[660][StreamProcessor][video] Next fragment request url for stream id defaultId_0 and media type video is https://example.com/output/video/avc1/seg-2.m4s dash.all.debug.js:18001:19
[688][PlaybackController] Native video element event: loadeddata dash.all.debug.js:18001:19
[691][PlaybackController] Native video element event: play dash.all.debug.js:18001:19
[692][StreamController] [onPlaybackStarted] dash.all.debug.js:18001:19
[693][PlaybackController] Native video element event: playing dash.all.debug.js:18001:19
[735][ScheduleController][video] Quality change rendered for streamId defaultId_0 and type video dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/seg-2.m4s
[HTTP/2 304 Not Modified 1ms]

[963][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/seg-2.m4s  dash.all.debug.js:18001:19
[966][AbrController] [video] switching from throughput to buffer occupancy ABR rule (buffer: 16.027). dash.all.debug.js:18001:19
[969][BufferController][video] Buffered range: 0 - 16.233333, currentTime =  0.20598 dash.all.debug.js:18001:19
[970][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[973][ScheduleController][video] Media segment needed for video and stream id defaultId_0 dash.all.debug.js:18001:19
[975][StreamProcessor][video] Next fragment request url for stream id defaultId_0 and media type video is https://example.com/output/video/avc1/seg-3.m4s dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/seg-3.m4s
[HTTP/2 304 Not Modified 1ms]

[1114][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/seg-3.m4s  dash.all.debug.js:18001:19
[1123][BufferController][video] Buffered range: 0 - 20.1, currentTime =  0.367161 dash.all.debug.js:18001:19
[1125][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[1126][ScheduleController][video] Media segment needed for video and stream id defaultId_0 dash.all.debug.js:18001:19
[1128][StreamProcessor][video] Next fragment request url for stream id defaultId_0 and media type video is https://example.com/output/video/avc1/seg-4.m4s dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/seg-4.m4s
[HTTP/2 304 Not Modified 1ms]

[1160][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/seg-4.m4s  dash.all.debug.js:18001:19
[1165][BufferController][video] Buffered range: 0 - 27.4, currentTime =  0.407271 dash.all.debug.js:18001:19
[1166][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[1167][ScheduleController][video] Media segment needed for video and stream id defaultId_0 dash.all.debug.js:18001:19
[1170][StreamProcessor][video] Next fragment request url for stream id defaultId_0 and media type video is https://example.com/output/video/avc1/seg-5.m4s dash.all.debug.js:18001:19
XHRGEThttps://example.com/output/video/avc1/seg-5.m4s
[HTTP/2 304 Not Modified 1ms]

[1471][StreamProcessor][video] OnFragmentLoadingCompleted for stream id defaultId_0 and media type video - Url: https://example.com/output/video/avc1/seg-5.m4s  dash.all.debug.js:18001:19
[1474][BufferController][video] Buffered range: 0 - 35.733333, currentTime =  0.73031 dash.all.debug.js:18001:19
[1476][ScheduleController][video] Appended bytes for video and stream id defaultId_0 dash.all.debug.js:18001:19
[1477][ScheduleController][video] Media segment needed for video and stream id defaultId_0 

One thought on “MPEG-DASH and ClearKey, CENC drm encryption with Nginx, bento4 and dashjs under CentOS 8”

  1. if install nginx + bento4 + clearkey + iptv admin panel, can it handle encrypt url from source so i can restream it ?

Leave a Reply

Your email address will not be published. Required fields are marked *