devine-dl / pywidevine

Python implementation of Google's Widevine DRM CDM (Content Decryption Module)
GNU General Public License v3.0
537 stars 118 forks source link

Use standard python xml.etree.ElementTree #35

Closed mediaminister closed 1 year ago

mediaminister commented 1 year ago

lxml needs a compiled binary and therefore it is more difficult to install pywidevine on ARM devices like Raspberry Pi. It's better to use standard xml.etree.ElementTree for xml parsing. This code even works on Python 2.7.

rlaphoenix commented 1 year ago

Have you tested PlayReady header parsing with your changes on each support PlayReady header version? I understand that I have no Python tests made yet (something I will do eventually).

mediaminister commented 1 year ago

Yes, I tested this:

# -*- coding: utf-8 -*-

from xml.etree.ElementTree import XML

def run():
    wrm_list = [
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.3.0.0">
          <DATA>
            <PROTECTINFO>
              <KIDS>
                <KID ALGID="AESCBC" VALUE="PV1LM/VEVk+kEOB8qqcWDg=="></KID>
                <KID ALGID="AESCBC" VALUE="tuhDoKUN7EyxDPtMRNmhyA=="></KID>
              </KIDS>
            </PROTECTINFO>
            <LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL>
            <DS_ID>AH+03juKbUGbHl1V/QIwRA==</DS_ID>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.3.0.0">
          <DATA>
            <PROTECTINFO>
              <KIDS>
                <KID VALUE="PV1LM/VEVk+kEOB8qqcWDg=="></KID>
              </KIDS>
            </PROTECTINFO>
            <LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL>
            <DS_ID>AH+03juKbUGbHl1V/QIwRA==</DS_ID>
            <DECRYPTORSETUP>ONDEMAND</DECRYPTORSETUP>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.3.0.0">
          <DATA>
              <PROTECTINFO LICENSEREQUESTED="true">
                <KIDS>
                  <KID ALGID="value" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                  <KID ALGID="value" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                  <KID ALGID="value" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                </KIDS>
              </PROTECTINFO>
              <LA_URL> URL for license acquisition </LA_URL>
              <LUI_URL>
                URL for Non-silent license acquisition web page
              </LUI_URL>
            <DS_ID> base64-encoded guid </DS_ID>
            <CUSTOMATTRIBUTES xmlns="">
              <mm:Publisher xmlns:mm="urn:schema-musicmogul-com">
                   <mm:Author>
                        Elvis Presley
                   </mm:Author>
                   <mm:CreationDate>
                        2007/08/21:12:00:00
                   </mm:CreationDate>
                </mm:Publisher>
            </CUSTOMATTRIBUTES>
            <DECRYPTORSETUP>ONDEMAND</DECRYPTORSETUP>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.2.0.0">
          <DATA>
            <PROTECTINFO>
              <KIDS>
                <KID ALGID="AESCTR" CHECKSUM="xNvWVxoWk04=" VALUE="0IbHou/5s0yzM80yOkKEpQ=="></KID>
                <KID ALGID="AESCTR" CHECKSUM="GnKaQIRacPU=" VALUE="/qgG2xbs4k2SKCxx6bhWqw=="></KID>
              </KIDS>
            </PROTECTINFO>
            <LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL>
            <DS_ID>AH+03juKbUGbHl1V/QIwRA==</DS_ID>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.2.0.0">
          <DATA>
              <PROTECTINFO>
                <KIDS>
                  <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                  <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                  <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
                </KIDS>
              </PROTECTINFO>
              <LA_URL> URL for license acquisition </LA_URL>
              <LUI_URL>
                URL for Non-silent license acquisition web page
              </LUI_URL>
            <DS_ID> base64-encoded guid </DS_ID>
            <CUSTOMATTRIBUTES xmlns="">
              <mm:Publisher xmlns:mm="urn:schema-musicmogul-com">
                   <mm:Author>
                        Elvis Presley
                   </mm:Author>
                   <mm:CreationDate>
                        2007/08/21:12:00:00
                   </mm:CreationDate>
                </mm:Publisher>
            </CUSTOMATTRIBUTES>
            <DECRYPTORSETUP>ONDEMAND</DECRYPTORSETUP>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.1.0.0">
          <DATA>
              <PROTECTINFO>
                <KID ALGID="AESCTR" CHECKSUM="base64-encoded value" VALUE="base64-encoded guid"></KID>
              </PROTECTINFO>
              <LA_URL> URL for license acquisition </LA_URL>
              <LUI_URL>
                URL for Non-silent license acquisition web page
              </LUI_URL>
            <DS_ID> base64-encoded guid </DS_ID>
            <CUSTOMATTRIBUTES xmlns="">
              <mm:Publisher xmlns:mm="urn:schema-musicmogul-com">
                   <mm:Author>
                        Elvis Presley
                   </mm:Author>
                   <mm:CreationDate>
                        2007/08/21:12:00:00
                   </mm:CreationDate>
                </mm:Publisher>
            </CUSTOMATTRIBUTES>
            <DECRYPTORSETUP>ONDEMAND</DECRYPTORSETUP>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0">
          <DATA>
            <PROTECTINFO>
              <ALGID>AESCTR</ALGID>
              <KEYLEN>16</KEYLEN>
            </PROTECTINFO>
            <KID>q5HgCTj40kGeNVhTH9Gexw==</KID>
            <CHECKSUM>w+OZVr8vzrQ=</CHECKSUM>
            <LA_URL>http://rm.contoso.com/rightsmanager.asmx</LA_URL>
            <CUSTOMATTRIBUTES>
              <IIS_DRM_VERSION>8.0.1705.19</IIS_DRM_VERSION>
            </CUSTOMATTRIBUTES>
          </DATA>
        </WRMHEADER>
    """,
    """
        <WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0">
        <DATA>
              <PROTECTINFO>
                <ALGID>AESCTR</ALGID>
                <KEYLEN>16</KEYLEN>
              </PROTECTINFO>
              <LA_URL> URL for license acquisition </LA_URL>
              <LUI_URL>
                URL for Non-silent license acquisition web page
              </LUI_URL>
            <DS_ID>base64-encoded guid</DS_ID>
            <KID>base64-encoded kid</KID>
            <CUSTOMATTRIBUTES xmlns="">
              <mm:Publisher xmlns:mm="urn:schema-musicmogul-com">
                   <mm:Author>
                        Elvis Presley
                   </mm:Author>
                   <mm:CreationDate>
                        2007/08/21:12:00:00
                   </mm:CreationDate>
                </mm:Publisher>
            </CUSTOMATTRIBUTES>
            <CHECKSUM>
              checksum of the content key for verification
            </CHECKSUM>
          </DATA>
        </WRMHEADER>
    """
    ]
    for wrm in wrm_list:
        wrm_ns = {"wrm": "http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader"}
        prr_header = XML(wrm)
        prr_header_version = prr_header.get("version")
        if prr_header_version == "4.0.0.0":
            key_ids = [
                x.text
                for x in prr_header.findall("./wrm:DATA/wrm:KID", wrm_ns)
            ]
        elif prr_header_version == "4.1.0.0":
            key_ids = [
                x.get("VALUE")
                for x in prr_header.findall("./wrm:DATA/wrm:PROTECTINFO/wrm:KID", wrm_ns)
            ]
        elif prr_header_version in ("4.2.0.0", "4.3.0.0"):
            # TODO: Retain the Encryption Scheme information in v4.3.0.0
            #       This is because some Key IDs can be AES-CTR while some are AES-CBC.
            #       Conversion to WidevineCencHeader could use this information.
            key_ids = [
                x.get("VALUE")
                for x in prr_header.findall("./wrm:DATA/wrm:PROTECTINFO/wrm:KIDS/wrm:KID", wrm_ns)
            ]

        print(prr_header_version)
        print(key_ids)

if __name__ == '__main__':
    run()