2026-04-24 06:01:21 +02:00
# pywv
2026-04-24 06:06:50 +02:00
**pywv** is a Python-based tool for parsing, analyzing, and interacting with **Widevine (WVD) device files** and associated DRM structures. It provides low-level access to device data, cryptographic components, and license-related metadata, enabling precise inspection and controlled handling of Widevine workflows.
---
## Features
* Parsing and loading of **Widevine Device (WVD) files**
* Support for **WVD version migration (v1 → v2)**
* Extraction of **device attributes** (system ID, security level, client identification)
* Decoding of **Widevine protobuf structures** (ClientIdentification, certificates, licenses)
* Integration with **cryptographic primitives** (RSA, AES, CMAC, HMAC)
* Parsing and manipulation of **PSSH (Widevine / PlayReady)** containers
* License processing and **content key extraction** via CDM workflows
---
## Requirements
* Python 3.9 or higher
* `pycryptodome`
* `construct`
* `protobuf`
* `pymp4`
* `requests`
Installation:
```bash
pip install pycryptodome construct protobuf pymp4 requests
```
---
## Usage
```bash
python pywv.py [ options]
```
---
## Examples
### Basic Usage
```python
import requests
from pywv import PSSH , Device , Cdm
pssh = PSSH ( "AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==" )
device = Device . load ( "xiaomi_redmi_note_4x_15.0.0_e15a9e5f_8159_l3.wvd" )
cdm = Cdm . from_device ( device )
session_id = cdm . open ()
try :
challenge = cdm . get_license_challenge ( session_id , pssh )
license_response = requests . post (
"https://cwip-shaka-proxy.appspot.com/no_auth" ,
data = challenge ,
)
license_response . raise_for_status ()
cdm . parse_license ( session_id , license_response . content )
for key in cdm . get_keys ( session_id ):
print ( f "[ { key . type } ] { key . kid . hex } : { key . key . hex () } " )
finally :
cdm . close ( session_id )
```
---
### Using JSON Device Configuration
```python
# wv.json example:
# {
# "security_level": 3,
# "session_id_type": "android",
# "private_key_available": true,
# "vmp": false
# }
import json
import requests
from pathlib import Path
from pywv import PSSH , Device , Cdm
base_path = Path ( __file__ ) . resolve () . parent
with open ( base_path / "wv.json" , "r" , encoding = "utf-8" ) as f :
wv = json . load ( f )
pssh = PSSH ( "AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==" )
if not wv . get ( "private_key_available" , True ):
raise ValueError ( "This device profile does not include a private key" )
device_kwargs = {
"private_key" : base_path / "device_private_key" ,
"client_id" : base_path / "device_client_id_blob" ,
"type_" : wv . get ( "session_id_type" , "ANDROID" ) . upper (),
"security_level" : wv . get ( "security_level" , 3 ),
}
vmp_path = base_path / "device_vmp_blob"
if wv . get ( "vmp" , False ) and vmp_path . exists ():
device_kwargs [ "vmp" ] = vmp_path
device = Device . from_files ( ** device_kwargs )
cdm = Cdm . from_device ( device )
session_id = cdm . open ()
try :
challenge = cdm . get_license_challenge ( session_id , pssh )
license_response = requests . post (
"https://cwip-shaka-proxy.appspot.com/no_auth" ,
data = challenge ,
)
license_response . raise_for_status ()
cdm . parse_license ( session_id , license_response . content )
for key in cdm . get_keys ( session_id ):
print ( f "[ { key . type } ] { key . kid . hex } : { key . key . hex () } " )
finally :
cdm . close ( session_id )
```
---
## Disclaimer
This tool is intended strictly for **educational, research, and interoperability purposes** .
The author does not support or encourage the misuse of DRM systems or unauthorized access to protected content.
---
## Issues and Support
For bug reports, feature requests, or general inquiries, please open an issue in the repository.
Support and updates will be provided as availability permits.
---
## Acknowledgements
This project is **based on pywidevine** , with modifications and restructuring to support standalone usage and extended functionality for working with WVD and PSSH data.