pywidevine


Namepywidevine JSON
Version 1.8.0 PyPI version JSON
download
home_pagehttps://github.com/devine-dl/pywidevine
SummaryWidevine CDM (Content Decryption Module) implementation in Python.
upload_time2023-12-22 11:13:12
maintainer
docs_urlNone
authorrlaphoenix
requires_python>=3.8,<4.0
licenseGPL-3.0-only
keywords python drm widevine google
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
    <img src="docs/images/widevine_icon_24.png"> <a href="https://github.com/devine-dl/pywidevine">pywidevine</a>
    <br/>
    <sup><em>Python Widevine CDM implementation</em></sup>
</p>

<p align="center">
    <a href="https://github.com/devine-dl/pywidevine/actions/workflows/ci.yml">
        <img src="https://github.com/devine-dl/pywidevine/actions/workflows/ci.yml/badge.svg" alt="Build status">
    </a>
    <a href="https://pypi.org/project/pywidevine">
        <img src="https://img.shields.io/badge/python-3.8%2B-informational" alt="Python version">
    </a>
    <a href="https://deepsource.io/gh/devine-dl/pywidevine">
        <img src="https://deepsource.io/gh/devine-dl/pywidevine.svg/?label=active+issues" alt="DeepSource">
    </a>
</p>
<p align="center">
    <a href="https://github.com/astral-sh/ruff">
        <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Linter: Ruff">
    </a>
    <a href="https://python-poetry.org">
        <img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Dependency management: Poetry">
    </a>
</p>

## Features

- 🚀 Seamless Installation via [pip](#installation)
- 🛡️ Robust Security with message signature verification
- 🙈 Privacy Mode with Service Certificates
- 🌐 Servable CDM API Server and Client with Authentication
- 📦 Custom provision serialization format (WVD v2)
- 🧰 Create, parse, or convert PSSH headers with ease
- 🗃️ User-friendly YAML configuration
- ❤️ Forever FOSS!

## Installation

```shell
$ pip install pywidevine
```

> **Note**
If pip gives you a warning about a path not being in your PATH environment variable then promptly add that path then
close all open command prompt/terminal windows, or `pywidevine` CLI won't work as it will not be found.

Voilà 🎉 — You now have the `pywidevine` package installed!  
You can now import pywidevine in scripts ([see below](#usage)).  
A command-line interface is also available, try `pywidevine --help`.

## Usage

The following is a minimal example of using pywidevine in a script to get a License for Bitmovin's
Art of Motion Demo.

```py
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH

import requests

# prepare pssh
pssh = PSSH("AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa"
            "7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==")

# load device
device = Device.load("C:/Path/To/A/Provision.wvd")

# load cdm
cdm = Cdm.from_device(device)

# open cdm session
session_id = cdm.open()

# get license challenge
challenge = cdm.get_license_challenge(session_id, pssh)

# send license challenge (assuming a generic license server SDK with no API front)
licence = requests.post("https://...", data=challenge)
licence.raise_for_status()

# parse license challenge
cdm.parse_license(session_id, licence.content)

# print keys
for key in cdm.get_keys(session_id):
    print(f"[{key.type}] {key.kid.hex}:{key.key.hex()}")

# close session, disposes of session data
cdm.close(session_id)
```

> **Note**
> There are various features not shown in this specific example like:
>
> - Privacy Mode
> - Setting Service Certificates
> - Remote CDMs and Serving
> - Choosing a License Type to request
> - Creating WVD files
> - and much more!
>
> Take a look at the methods available in the [Cdm class](/pywidevine/cdm.py) and their doc-strings for
> further information. For more examples see the [CLI functions](/pywidevine/main.py) which uses a lot
> of previously mentioned features.

## Disclaimer

1. This project requires a valid Google-provisioned Private Key and Client Identification blob which are not
   provided by this project.
2. Public test provisions are available and provided by Google to use for testing projects such as this one.
3. License Servers have the ability to block requests from any provision, and are likely already blocking test
   provisions on production endpoints.
4. This project does not condone piracy or any action against the terms of the DRM systems.
5. All efforts in this project have been the result of Reverse-Engineering, Publicly available research, and Trial
   & Error.

## Key and Output Security

*Licenses, Content Keys, and Decrypted Data is not secure in this CDM implementation.*

The Content Decryption Module is meant to do all downloading, decrypting, and decoding of content, not just license
acquisition. This Python implementation only does License Acquisition within the CDM.

The section of which a 'Decrypt Frame' call is made would be more of a 'Decrypt File' in this implementation. Just
returning the original file in plain text defeats the point of the DRM. Even if 'Decrypt File' was somehow secure, the
Content Keys used to decrypt the files are already exposed to the caller anyway, allowing them to manually decrypt.

An attack on a 'Decrypt Frame' system would be analogous to doing an HDMI capture or similar attack. This is because it
would require re-encoding the video by splicing each individual frame with the right frame-rate, syncing to audio, and
more.

While a 'Decrypt Video' system would be analogous to downloading a Video and passing it through a script. Not much of
an attack if at all. The only protection against a system like this would be monitoring the provision and acquisitions
of licenses and prevent them. This can be done by revoking the device provision, or the user or their authorization to
the service.

There isn't any immediate way to secure either Key or Decrypted information within a Python environment that is not
Hardware backed. Even if obfuscation or some other form of Security by Obscurity was used, this is a Software-based
Content Protection Module (in Python no less) with no hardware backed security. It would be incredibly trivial to break
any sort of protection against retrieving the original video data.

Though, it's not impossible. Google's Chrome Browser CDM is a simple library extension file programmed in C++ that has
been improving its security using math and obscurity for years. It's getting harder and harder to break with its latest
versions only being beaten by Brute-force style methods. However, they have a huge team of very skilled workers, and
making a CDM in C++ has immediate security benefits and a lot of methods to obscure and obfuscate the code.

## Contributors

<a href="https://github.com/rlaphoenix"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/17136956?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
<a href="https://github.com/mediaminister"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/45148099?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
<a href="https://github.com/sr0lle"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/111277375?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>

## Licensing

This software is licensed under the terms of [GNU General Public License, Version 3.0](LICENSE).  
You can find a copy of the license in the LICENSE file in the root folder.

- Widevine Icon &copy; Google.
- Props to the awesome community for their shared research and insight into the Widevine Protocol and Key Derivation.

* * *

© rlaphoenix 2022-2023

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/devine-dl/pywidevine",
    "name": "pywidevine",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "python,drm,widevine,google",
    "author": "rlaphoenix",
    "author_email": "rlaphoenix@pm.me",
    "download_url": "https://files.pythonhosted.org/packages/99/12/6ff0e6ffa2711187ee629392396d7c18ae6ca8e2e576dcef2d636316d667/pywidevine-1.8.0.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\n    <img src=\"docs/images/widevine_icon_24.png\"> <a href=\"https://github.com/devine-dl/pywidevine\">pywidevine</a>\n    <br/>\n    <sup><em>Python Widevine CDM implementation</em></sup>\n</p>\n\n<p align=\"center\">\n    <a href=\"https://github.com/devine-dl/pywidevine/actions/workflows/ci.yml\">\n        <img src=\"https://github.com/devine-dl/pywidevine/actions/workflows/ci.yml/badge.svg\" alt=\"Build status\">\n    </a>\n    <a href=\"https://pypi.org/project/pywidevine\">\n        <img src=\"https://img.shields.io/badge/python-3.8%2B-informational\" alt=\"Python version\">\n    </a>\n    <a href=\"https://deepsource.io/gh/devine-dl/pywidevine\">\n        <img src=\"https://deepsource.io/gh/devine-dl/pywidevine.svg/?label=active+issues\" alt=\"DeepSource\">\n    </a>\n</p>\n<p align=\"center\">\n    <a href=\"https://github.com/astral-sh/ruff\">\n        <img src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\" alt=\"Linter: Ruff\">\n    </a>\n    <a href=\"https://python-poetry.org\">\n        <img src=\"https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json\" alt=\"Dependency management: Poetry\">\n    </a>\n</p>\n\n## Features\n\n- \ud83d\ude80 Seamless Installation via [pip](#installation)\n- \ud83d\udee1\ufe0f Robust Security with message signature verification\n- \ud83d\ude48 Privacy Mode with Service Certificates\n- \ud83c\udf10 Servable CDM API Server and Client with Authentication\n- \ud83d\udce6 Custom provision serialization format (WVD v2)\n- \ud83e\uddf0 Create, parse, or convert PSSH headers with ease\n- \ud83d\uddc3\ufe0f User-friendly YAML configuration\n- \u2764\ufe0f Forever FOSS!\n\n## Installation\n\n```shell\n$ pip install pywidevine\n```\n\n> **Note**\nIf pip gives you a warning about a path not being in your PATH environment variable then promptly add that path then\nclose all open command prompt/terminal windows, or `pywidevine` CLI won't work as it will not be found.\n\nVoil\u00e0 \ud83c\udf89 \u2014 You now have the `pywidevine` package installed!  \nYou can now import pywidevine in scripts ([see below](#usage)).  \nA command-line interface is also available, try `pywidevine --help`.\n\n## Usage\n\nThe following is a minimal example of using pywidevine in a script to get a License for Bitmovin's\nArt of Motion Demo.\n\n```py\nfrom pywidevine.cdm import Cdm\nfrom pywidevine.device import Device\nfrom pywidevine.pssh import PSSH\n\nimport requests\n\n# prepare pssh\npssh = PSSH(\"AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa\"\n            \"7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==\")\n\n# load device\ndevice = Device.load(\"C:/Path/To/A/Provision.wvd\")\n\n# load cdm\ncdm = Cdm.from_device(device)\n\n# open cdm session\nsession_id = cdm.open()\n\n# get license challenge\nchallenge = cdm.get_license_challenge(session_id, pssh)\n\n# send license challenge (assuming a generic license server SDK with no API front)\nlicence = requests.post(\"https://...\", data=challenge)\nlicence.raise_for_status()\n\n# parse license challenge\ncdm.parse_license(session_id, licence.content)\n\n# print keys\nfor key in cdm.get_keys(session_id):\n    print(f\"[{key.type}] {key.kid.hex}:{key.key.hex()}\")\n\n# close session, disposes of session data\ncdm.close(session_id)\n```\n\n> **Note**\n> There are various features not shown in this specific example like:\n>\n> - Privacy Mode\n> - Setting Service Certificates\n> - Remote CDMs and Serving\n> - Choosing a License Type to request\n> - Creating WVD files\n> - and much more!\n>\n> Take a look at the methods available in the [Cdm class](/pywidevine/cdm.py) and their doc-strings for\n> further information. For more examples see the [CLI functions](/pywidevine/main.py) which uses a lot\n> of previously mentioned features.\n\n## Disclaimer\n\n1. This project requires a valid Google-provisioned Private Key and Client Identification blob which are not\n   provided by this project.\n2. Public test provisions are available and provided by Google to use for testing projects such as this one.\n3. License Servers have the ability to block requests from any provision, and are likely already blocking test\n   provisions on production endpoints.\n4. This project does not condone piracy or any action against the terms of the DRM systems.\n5. All efforts in this project have been the result of Reverse-Engineering, Publicly available research, and Trial\n   & Error.\n\n## Key and Output Security\n\n*Licenses, Content Keys, and Decrypted Data is not secure in this CDM implementation.*\n\nThe Content Decryption Module is meant to do all downloading, decrypting, and decoding of content, not just license\nacquisition. This Python implementation only does License Acquisition within the CDM.\n\nThe section of which a 'Decrypt Frame' call is made would be more of a 'Decrypt File' in this implementation. Just\nreturning the original file in plain text defeats the point of the DRM. Even if 'Decrypt File' was somehow secure, the\nContent Keys used to decrypt the files are already exposed to the caller anyway, allowing them to manually decrypt.\n\nAn attack on a 'Decrypt Frame' system would be analogous to doing an HDMI capture or similar attack. This is because it\nwould require re-encoding the video by splicing each individual frame with the right frame-rate, syncing to audio, and\nmore.\n\nWhile a 'Decrypt Video' system would be analogous to downloading a Video and passing it through a script. Not much of\nan attack if at all. The only protection against a system like this would be monitoring the provision and acquisitions\nof licenses and prevent them. This can be done by revoking the device provision, or the user or their authorization to\nthe service.\n\nThere isn't any immediate way to secure either Key or Decrypted information within a Python environment that is not\nHardware backed. Even if obfuscation or some other form of Security by Obscurity was used, this is a Software-based\nContent Protection Module (in Python no less) with no hardware backed security. It would be incredibly trivial to break\nany sort of protection against retrieving the original video data.\n\nThough, it's not impossible. Google's Chrome Browser CDM is a simple library extension file programmed in C++ that has\nbeen improving its security using math and obscurity for years. It's getting harder and harder to break with its latest\nversions only being beaten by Brute-force style methods. However, they have a huge team of very skilled workers, and\nmaking a CDM in C++ has immediate security benefits and a lot of methods to obscure and obfuscate the code.\n\n## Contributors\n\n<a href=\"https://github.com/rlaphoenix\"><img src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/17136956?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d\" alt=\"\"/></a>\n<a href=\"https://github.com/mediaminister\"><img src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/45148099?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d\" alt=\"\"/></a>\n<a href=\"https://github.com/sr0lle\"><img src=\"https://images.weserv.nl/?url=avatars.githubusercontent.com/u/111277375?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d\" alt=\"\"/></a>\n\n## Licensing\n\nThis software is licensed under the terms of [GNU General Public License, Version 3.0](LICENSE).  \nYou can find a copy of the license in the LICENSE file in the root folder.\n\n- Widevine Icon &copy; Google.\n- Props to the awesome community for their shared research and insight into the Widevine Protocol and Key Derivation.\n\n* * *\n\n\u00a9 rlaphoenix 2022-2023\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-only",
    "summary": "Widevine CDM (Content Decryption Module) implementation in Python.",
    "version": "1.8.0",
    "project_urls": {
        "Changelog": "https://github.com/devine-dl/pywidevine/blob/master/CHANGELOG.md",
        "Discussions": "https://github.com/devine-dl/pywidevine/discussions",
        "Homepage": "https://github.com/devine-dl/pywidevine",
        "Issues": "https://github.com/devine-dl/pywidevine/issues",
        "Repository": "https://github.com/devine-dl/pywidevine"
    },
    "split_keywords": [
        "python",
        "drm",
        "widevine",
        "google"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "419f60f8a4c8e7767a8c34f5c42428662e03fa3e38ad18ba41fcc5370ee43263",
                "md5": "d420e4747e4ec4f93544202e02fa1299",
                "sha256": "1ecf029ce562789b18bbbd64604596d15645aadf413b255cf0fafc8d8b06659d"
            },
            "downloads": -1,
            "filename": "pywidevine-1.8.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d420e4747e4ec4f93544202e02fa1299",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 70476,
            "upload_time": "2023-12-22T11:13:10",
            "upload_time_iso_8601": "2023-12-22T11:13:10.840129Z",
            "url": "https://files.pythonhosted.org/packages/41/9f/60f8a4c8e7767a8c34f5c42428662e03fa3e38ad18ba41fcc5370ee43263/pywidevine-1.8.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "99126ff0e6ffa2711187ee629392396d7c18ae6ca8e2e576dcef2d636316d667",
                "md5": "911e475f5cfc182507895dce5fd302d7",
                "sha256": "c14f3fe2864473416b9caa73d9a21251a02d72138e6d54d8c1a3f44b7a6b05c9"
            },
            "downloads": -1,
            "filename": "pywidevine-1.8.0.tar.gz",
            "has_sig": false,
            "md5_digest": "911e475f5cfc182507895dce5fd302d7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 76406,
            "upload_time": "2023-12-22T11:13:12",
            "upload_time_iso_8601": "2023-12-22T11:13:12.556063Z",
            "url": "https://files.pythonhosted.org/packages/99/12/6ff0e6ffa2711187ee629392396d7c18ae6ca8e2e576dcef2d636316d667/pywidevine-1.8.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-22 11:13:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "devine-dl",
    "github_project": "pywidevine",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pywidevine"
}
        
Elapsed time: 0.19158s