Add Widevine Key Class

This commit is contained in:
rlaphoenix 2022-07-20 14:38:35 +01:00
parent 5c9d4cda73
commit 9331f4efc1
1 changed files with 63 additions and 0 deletions

63
pywidevine/key.py Normal file
View File

@ -0,0 +1,63 @@
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.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)