Encrypt your content with NAGRA MDRM
1. Introduction
Encrypting video with DRM protection can be a challenging topic to get started with, compared with other streaming video topics given the complexity and specialized need for such usage.
This tutorial will guide you through the process of creating a secure video stream from a source video to fully encrypted output with the NAGRA Multi-DRM (MDRM) service using freely available tools. NAGRA's Multi-DRM service is integrated with many leading packagers for a more integrated workflow. What will be shown here is the complete key generation process without the use of any packager pre-integration.
For this guide we will use the following tools:
ffmpeg (https://ffmpeg.org/download.html)
Shaka Packager (https://github.com/google/shaka-packager/releases)
Chrome, Edge, Firefox or any browser that is not Safari
Big Buck Bunny video (https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4.zip)
Note that for Shaka Packager, the executable name may vary depending on the platform used, e.g., packager-win
on Windows and packager-osx
on macOS.
First, let's generate our content.
2. Content preparation
For this tutorial, the widely used Big Buck Bunny video will be the source video, however, you can substitute any MP4 video here. The source video will be transformed into a DASH adaptive video stream with Widevine and PlayReady DRM, but the process is very similar for HLS and Fairplay. Producing a stream covering all three is possible with the MDRM service but is outside the scope of this tutorial.
The first step is to separate the audio from the video so that it can be delivered independent of the video. Extract the audio to its own file with the following command:
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -c:a copy -vn BBB-audio.mp4
The next step is to re-encode the source video from the highest quality and resolution down to the lowest across five different profiles 1080p, 720p, 480p, 360p, and finally 240p to provide the bitrate ladder for adaptation:
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -an -c:v libx264 -x264opts "keyint=24:min-keyint=24:no-scenecut" -b:v 5300k -maxrate 5300k -bufsize 2650k -vf "scale=-1:1080" BBB-1080.mp4
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -an -c:v libx264 -x264opts "keyint=24:min-keyint=24:no-scenecut" -b:v 2400k -maxrate 2400k -bufsize 1200k -vf "scale=-1:720" BBB-720.mp4
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -an -c:v libx264 -x264opts "keyint=24:min-keyint=24:no-scenecut" -b:v 1060k -maxrate 1060k -bufsize 530k -vf "scale=-1:478" BBB-480.mp4
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -an -c:v libx264 -x264opts "keyint=24:min-keyint=24:no-scenecut" -b:v 600k -maxrate 600k -bufsize 300k -vf "scale=-1:360" BBB-360.mp4
ffmpeg -i bbb_sunflower_1080p_30fps_normal.mp4 -an -c:v libx264 -x264opts "keyint=24:min-keyint=24:no-scenecut" -b:v 260k -maxrate 260k -bufsize 130k -vf "scale=-1:242" BBB-240.mp4
We now have all the raw video and audio content ready to be packaged into our DASH video. At this stage, the video could be packaged as clear content with the following command:
packager-win "in=BBB-audio.mp4,stream=audio,init_segment=dash/init.mp4,segment_template=dash/$Number$.m4s" "in=BBB-360.mp4,stream=video,init_segment=dash/level_1_init.mp4,segment_template=dash/level_1_$Number$.m4s" "in=BBB-480.mp4,stream=video,init_segment=dash/level_2_init.mp4,segment_template=dash/level_2_$Number$.m4s" "in=BBB-720.mp4,stream=video,init_segment=dash/level_3_init.mp4,segment_template=dash/level_3_$Number$.m4s" "in=BBB-1080.mp4,stream=video,init_segment=dash/level_4_init.mp4,segment_template=dash/level_4_$Number$.m4s" "in=BBB-240.mp4,stream=video,init_segment=dash/level_5_init.mp4,segment_template=dash/level_5_$Number$.m4s" --generate_static_live_mpd --mpd_output dash/manifest.mpd
The content in clear is now ready. The next step is to encrypt it and for this, we need to interact with the NAGRA Key Server.
3. Generating the encrypted content
To encrypt the video as part of the packaging process requires some additional command line parameters. For the purpose of this tutorial, we are going to use the raw key method (--enable_raw_key_encryption
), where we generate and insert the encryption key into the Key Server first, then encrypt the content offline without any further interaction needed with the Key Server.
To build the request to retrieve the content key from the NAGRA MDRM Key Server, we need the following elements:
Identify the URL of the Key Server in your lab or production system. See Key Server URLs.
Build an SSP token to authenticate your request.
Select the following fields for the request body:
Content ID – for example, "BigBuckBunny"
Content format – in this case, use "DASH".
Content type – in this case, use "VOD".
Encryption method – in this case, use 16420 for DASH common encryption (CTR).
DRMs – select the OTT Content Preparation for which you expect the key server to generate DRM signaling. For this guide, use Widevine (edef8ba9-79d6-4ace-a3c8-27dcd51d21ed) and PlayReady (9a04f079-9840-4286-ab92-e65be0885f95).
The resulting request body should look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="drm:KeyAndSignalization/v1/schemas" xmlns:sch1="drm:MultiDrmCommon/v1/schemas">
<soapenv:Header/>
<soapenv:Body>
<sch:GetKeyAndSignalizationRequest>
<sch:drmContent>
<sch1:drmContentId>BigBuckBunny</sch1:drmContentId>
<sch1:profile>
<sch1:distributionMode>VOD</sch1:distributionMode><sch1:streamingMode>DASH</sch1:streamingMode><sch1:cryptoPeriod>0</sch1:cryptoPeriod><sch1:emi>16420</sch1:emi>
</sch1:profile>
</sch:drmContent>
<sch:drmList>
<sch1:drm>
<sch1:drmSystemId>edef8ba9-79d6-4ace-a3c8-27dcd51d21ed</sch1:drmSystemId><sch1:drmName>WideVine</sch1:drmName>
</sch1:drm>
<sch1:drm>
<sch1:drmSystemId>9a04f079-9840-4286-ab92-e65be0885f95</sch1:drmSystemId><sch1:drmName>PLAYREADY</sch1:drmName>
</sch1:drm>
</sch:drmList>
</sch:GetKeyAndSignalizationRequest>
</soapenv:Body>
</soapenv:Envelope>
Send the HTTP request to the MDRM Key Server URL using your preferred tool (for example, curl or Postman).
Please ensure that you are including the following HTTP headers with the request:
Content-Type : text/xml
nv-authorizations : <base64 encoded SSP Authentication token>
The NAGRA Multi-DRM portal provides some tools to help you get started with interacting with the Key Server without requiring any complex setup. It generates all of the details required by a packager with a single button click. The complete mDRM documentation provides details on more advanced use cases and different Key Server API endpoints.

In the user-selectable fields, we need to fill in the following fields:
Content ID – a unique identifier for the content. Enter "BigBuckBunny".
Format – the streaming format you are preparing. In this case, select DASH.
Content Type – whether the content is on-demand (VOD) or live. Select VOD.
DRMs – the DRM schemes to be supported. Select Widevine and PlayReady.
Now click GENERATE KEY SERVER RESPONSE. This generates all the required information, as listed below.
The full request and response are available if required in the expanding Request Details and Response Details sections.
The key information we need from the Key Server response is:
keyId
:467adf69-9e74-48a7-9873-69d5c80194ed
key
:KCVZQ0mSoZN5ArorjiKbHw==
iv
:rtiDdoVpB0ojj82xkMmVag==
pssh
:AAAAQnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACIIARIQRnrfaZ50SKeYc2nVyAGU7SIMQmlnQnVja0J1bm55
Some post-processing of this data is needed to put it into a format we can use on the Shaka Packager command line. All of the input values are expected in a hexadecimal notation and not Base64 as above in the case of key, iv, and PSSH.
The keyId
is already in hexadecimal but must have the separating dashes (-) removed to become 467adf699e7448a7987369d5c80194ed
.
A useful online tool with client-side conversation of the Base64 data can be found here: https://cryptii.com/pipes/base64-to-hex. Make sure to change the Group By drop-down menu to select None to create a contiguous sequence.

In the above example, you can see that the key has been converted from the Base64 value of KCVZQ0mSoZN5ArorjiKbHw==
to a hexadecimal notation of 282559434992a1937902ba2b8e229b1f
. The same conversation needs to be performed on the iv to give the output of aed883768569074a238fcdb190c9956a
.
We can now put this together to form the --keys
parameter of the Shaka packager command line as shown below:
--keys label=:key_id=467adf699e7448a7987369d5c80194ed:key=282559434992a1937902ba2b8e229b1f:iv=aed883768569074a238fcdb190c9956a
The second step to encrypt the content is to provide the Protection System Specific Header (PSSH) box. This is also Base64-encoded in the XML and must be converted to hexadecimal notation and passed as a command line parameter like this:
--pssh 000000427073736800000000edef8ba979d64acea3c827dcd51d21ed0000002208011210467adf699e7448a7987369d5c80194ed220c4269674275636b42756e6e79
Finally, to ensure the content is encrypted from the very beginning the clear_lead
parameter should be explicitly set to 0:
--clear_lead 0
Now we can put our original command line together with all our encryption parameters to create the DASH content and encrypt it at the same time:
packager-win "in=BBB-audio.mp4,stream=audio,init_segment=dash/init.mp4,segment_template=dash/$Number$.m4s" "in=BBB-360.mp4,stream=video,init_segment=dash/level_1_init.mp4,segment_template=dash/level_1_$Number$.m4s" "in=BBB-480.mp4,stream=video,init_segment=dash/level_2_init.mp4,segment_template=dash/level_2_$Number$.m4s" "in=BBB-720.mp4,stream=video,init_segment=dash/level_3_init.mp4,segment_template=dash/level_3_$Number$.m4s" "in=BBB-1080.mp4,stream=video,init_segment=dash/level_4_init.mp4,segment_template=dash/level_4_$Number$.m4s" "in=BBB-240.mp4,stream=video,init_segment=dash/level_5_init.mp4,segment_template=dash/level_5_$Number$.m4s" --generate_static_live_mpd --mpd_output dash/manifest.mpd -clear_lead 0 --enable_raw_key_encryption --keys label=:key_id=467adf699e7448a7987369d5c80194ed:key=282559434992a1937902ba2b8e229b1f:iv=aed883768569074a238fcdb190c9956a --pssh 000000427073736800000000edef8ba979d64acea3c827dcd51d21ed0000002208011210467adf699e7448a7987369d5c80194ed220c4269674275636b42756e6e79
With the content now created and encrypted, it is time to test it.
4. Testing encrypted playback
First, let's make sure our content is accessible for playback. You should ensure you have a web server running with access to your output directory.
A quick-start solution, if you have Node installed, is to use the http-server
package (run npm install --global http-server
). Another option is to host the content from an AWS S3 bucket with the appropriate ACL enabled.
Note that DRM-encrypted content must be served via HTTPS unless you are using localhost
or 127.0.0.1
.
You should also enable CORS to prevent the browser blocking your requests due to cross-domain rules. In Node, you can do this with http-server
by running the command http-server --cors
. With AWS S3, the AWS console offers a CORS configuration editor.
To play back the content, follow the (23.48) License Server integration (under the Play your Own Content section) including the available HTML players, using the URL of the encrypted video content, that is, the full URL to the manifest.mpd
file generated above.
Please remember to generate an SSP content authorization token for "BigBuckBunny" and insert it in the "token" text field included with the HTML player. (The player takes care of generating the nv-authorizations
HTTP header with the HTTP request.)
To play back the content, you must first enter the URL of the video content, that is, the full URL to the manifest.mpd
file. Now enter the same Content ID as used during the key generation stage, in our case, "BigBuckBunny". Click Generate Playback Token to create a playback token to be used to authorise playback. This token can be re-used for as long as it is valid. Now click Test Playback Content. If everything was successful, then Big Buck Bunny should start playing.
4.1. Troubleshooting
If you do not see successful playback, take the following three steps:
Look for any on-screen errors that might give a clue as to what the problem is.
Open the Developer Tools and check for playback errors in the console – some of your inputs may be wrong or the server may have returned an error.
Try playback again with the Network tab open and see if any requests failed. If any files failed to load, this may halt playback. If a remote endpoint such as "license" returned an error, e.g., HTTP 500, then there may be a problem with the license or the request for one.
DRM is usually a case of outright success or failure. If there are problems, then carefully retrace your steps and look carefully for errors – a simple mistake can easily cause issues.