mirror of
				https://github.com/devine-dl/pywidevine.git
				synced 2025-11-04 03:44:50 +00:00 
			
		
		
		
	Add Widevine Key Class
This commit is contained in:
		
							parent
							
								
									5c9d4cda73
								
							
						
					
					
						commit
						9331f4efc1
					
				
							
								
								
									
										63
									
								
								pywidevine/key.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								pywidevine/key.py
									
									
									
									
									
										Normal 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)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user