mirror of
https://github.com/devine-dl/pywidevine.git
synced 2024-10-30 05:29:21 +00:00
67 lines
2.0 KiB
Python
67 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
from typing import Optional, Union
|
|
from uuid import UUID
|
|
|
|
from Crypto.Cipher import AES
|
|
from Crypto.Util import Padding
|
|
|
|
from pywidevine.license_protocol_pb2 import License
|
|
|
|
|
|
class Key:
|
|
def __init__(self, type_: str, kid: UUID, key: bytes, permissions: Optional[list[str]] = None):
|
|
self.type = type_
|
|
self.kid = kid
|
|
self.key = key
|
|
self.permissions = permissions or []
|
|
|
|
def __repr__(self) -> str:
|
|
return "{name}({items})".format(
|
|
name=self.__class__.__name__,
|
|
items=", ".join([f"{k}={repr(v)}" for k, v in self.__dict__.items()])
|
|
)
|
|
|
|
@classmethod
|
|
def from_key_container(cls, key: License.KeyContainer, enc_key: bytes) -> Key:
|
|
"""Load Key from a KeyContainer object."""
|
|
permissions = []
|
|
if key.type == License.KeyContainer.KeyType.Value("OPERATOR_SESSION"):
|
|
for descriptor, value in key.operator_session_key_permissions.ListFields():
|
|
if value == 1:
|
|
permissions.append(descriptor.name)
|
|
|
|
return Key(
|
|
type_=License.KeyContainer.KeyType.Name(key.type),
|
|
kid=cls.kid_to_uuid(key.id),
|
|
key=Padding.unpad(
|
|
AES.new(enc_key, AES.MODE_CBC, iv=key.iv).decrypt(key.key),
|
|
16
|
|
),
|
|
permissions=permissions
|
|
)
|
|
|
|
@staticmethod
|
|
def kid_to_uuid(kid: Union[str, bytes]) -> UUID:
|
|
"""
|
|
Convert a Key ID from a string or bytes to a UUID object.
|
|
At first this may seem very simple but some types of Key IDs
|
|
may not be 16 bytes and some may be decimal vs. hex.
|
|
"""
|
|
if isinstance(kid, str):
|
|
kid = base64.b64decode(kid)
|
|
if not kid:
|
|
kid = b"\x00" * 16
|
|
|
|
if kid.decode(errors="replace").isdigit():
|
|
return UUID(int=int(kid.decode()))
|
|
|
|
if len(kid) < 16:
|
|
kid += b"\x00" * (16 - len(kid))
|
|
|
|
return UUID(bytes=kid)
|
|
|
|
|
|
__all__ = ("Key",)
|