Add a playready_experiment.py to play with ProtectionHeader master
authorAntonio Ospite <ao2@ao2.it>
Fri, 15 Jan 2016 21:24:20 +0000 (22:24 +0100)
committerAntonio Ospite <ao2@ao2.it>
Fri, 15 Jan 2016 21:24:20 +0000 (22:24 +0100)
Just a script to explore the format of the ProtectionHeader element.

playready_experiment.py [new file with mode: 0755]

diff --git a/playready_experiment.py b/playready_experiment.py
new file mode 100755 (executable)
index 0000000..ed26906
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# playready_experiment.py - Example of SmoothStreaming PlayReady authentication
+#
+# Copyright (C) 2016  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#
+# Experiment on how to use the ProtectionHeader element in SmoothSTreaming
+# manifest files.
+#
+# The code is just a demonstration of how to decode the ProtectionHeader element
+# content, it is not supposed to do nothing actually useful.
+#
+# Based on the PlayReady Header Object specification:
+# http://download.microsoft.com/download/1/4/7/1475C862-6B67-44B2-AF31-ABC83EA68292/PlayReady%20Header%20Object%20(7-2-2012).docx
+
+import base64
+import struct
+import sys
+import xml.etree.ElementTree as etree
+
+from pysimplesoap.client import SoapClient
+from pysimplesoap.simplexml import SimpleXMLElement
+
+
+def get_right_management_header(protection_header_text):
+    play_ready_header_objects = base64.b64decode(protection_header_text)
+
+    offset = 0
+
+    field_size = 4
+    total_size = struct.unpack("<L", play_ready_header_objects[offset:offset + field_size])[0]
+    offset += field_size
+
+    if total_size != len(play_ready_header_objects):
+        sys.stderr.write("Error, unexpected size.\n")
+        sys.exit(1)
+
+    field_size = 2
+    count = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+    offset += field_size
+
+    for i in range(count):
+        field_size = 2
+        record_type = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+        offset += field_size
+
+        field_size = 2
+        record_length = struct.unpack("<H", play_ready_header_objects[offset:offset + field_size])[0]
+        offset += field_size
+
+        if record_type == 1:
+            right_management_header = play_ready_header_objects[offset:offset + record_length].decode("UTF-16")
+            return right_management_header
+        else:
+            sys.stderr.write("Error, unsupported record type. Skipping.\n")
+            offset += record_length
+
+
+def main():
+    if len(sys.argv) != 2:
+        sys.stderr.write("usage: %s <manifest>\n" % sys.argv[0])
+        sys.exit(1)
+
+    manifest_filename = sys.argv[1]
+
+    manifest = etree.parse(manifest_filename)
+    protection_header = manifest.find(".//Protection/ProtectionHeader")
+
+    challenge = get_right_management_header(protection_header.text)
+
+    challenge_xml = etree.fromstring(challenge)
+    la_url = challenge_xml.find(".//{http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader}LA_URL").text
+
+    client = SoapClient(
+        location=la_url,
+        action='http://schemas.microsoft.com/DRM/2007/03/protocols/',
+        soap_ns='soap', trace=True, ns=False)
+
+    params = SimpleXMLElement("""<AcquireLicense xmlns="http://schemas.microsoft.com/DRM/2007/03/protocols"><challenge>""" +
+                              challenge + 
+                              """</challenge></AcquireLicense>""")
+
+    response = client.call('AcquireLicense', params)
+    print(response)
+
+if __name__ == "__main__":
+    main()