diff --git a/pyplayready/__init__.py b/pyplayready/__init__.py index ec77f83..7351361 100644 --- a/pyplayready/__init__.py +++ b/pyplayready/__init__.py @@ -10,4 +10,4 @@ from .session import * from .xml_key import * from .xmrlicense import * -__version__ = "0.4.2" +__version__ = "0.4.3" diff --git a/pyplayready/bcert.py b/pyplayready/bcert.py index 2bb25ce..9bb6a1e 100644 --- a/pyplayready/bcert.py +++ b/pyplayready/bcert.py @@ -214,11 +214,6 @@ class Certificate(_BCertStructs): max_header: int = 15360, max_chain_depth: int = 2 ) -> Certificate: - if not cert_id: - raise ValueError("Certificate ID is required") - if not client_id: - raise ValueError("Client ID is required") - basic_info = Container( cert_id=cert_id, security_level=security_level, @@ -250,9 +245,20 @@ class Certificate(_BCertStructs): feature = Container( feature_count=3, features=ListContainer([ - 4, # SECURE_CLOCK - 9, # REVOCATION_LIST_FEATURE - 13 # SUPPORTS_PR3_FEATURES + # 1, # Transmitter + # 2, # Receiver + # 3, # SharedCertificate + 4, # SecureClock + 5, # AntiRollBackClock + # 6, # ReservedMetering + # 7, # ReservedLicSync + # 8, # ReservedSymOpt + 9, # CRLS (Revocation Lists) + # 10, # ServerBasicEdition + # 11, # ServerStandardEdition + # 12, # ServerPremiumEdition + 13, # PlayReady3Features + # 14, # DeprecatedSecureStop ]) ) feature_attribute = Container( @@ -385,8 +391,10 @@ class Certificate(_BCertStructs): return self._BCERT def verify_signature(self): - sign_payload = self.dumps()[:-144] - signature_attribute = self.get_attribute(8).attribute + signature_object = self.get_attribute(8) + signature_attribute = signature_object.attribute + + sign_payload = self.dumps()[:-signature_object.length] raw_signature_key = signature_attribute.signature_key signature_key = ECC.construct( diff --git a/pyplayready/ecc_key.py b/pyplayready/ecc_key.py index 8a39d0f..1fbf78b 100644 --- a/pyplayready/ecc_key.py +++ b/pyplayready/ecc_key.py @@ -56,15 +56,17 @@ class ECCKey: with Path(path).open(mode="rb") as f: return cls.loads(f.read()) - def dumps(self): + def dumps(self, private_only=False): + if private_only: + return self.private_bytes() return self.private_bytes() + self.public_bytes() - def dump(self, path: Union[Path, str]) -> None: + def dump(self, path: Union[Path, str], private_only=False) -> None: if not isinstance(path, (Path, str)): raise ValueError(f"Expecting Path object or path string, got {path!r}") path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(self.dumps()) + path.write_bytes(self.dumps(private_only)) def get_point(self, curve: Curve) -> Point: return Point(self.key.pointQ.x, self.key.pointQ.y, curve) diff --git a/pyplayready/key.py b/pyplayready/key.py index 23cde0f..54ecca0 100644 --- a/pyplayready/key.py +++ b/pyplayready/key.py @@ -12,6 +12,7 @@ class Key: AES_128_ECB = 0x0003 COCKTAIL = 0x0004 AES_128_CBC = 0x0005 + KEYEXCHANGE = 0x0006 UNKNOWN = 0xffff @classmethod @@ -24,7 +25,8 @@ class Key: CHAINED_LICENSE = 0x0002 ECC_256 = 0x0003 ECC_256_WITH_KZ = 0x0004 - SCALABLE = 0x0005 + TEE_TRANSIENT = 0x0005 + ECC_256_VIA_SYMMETRIC = 0x0006 UNKNOWN = 0xffff @classmethod diff --git a/pyplayready/main.py b/pyplayready/main.py index 0a691f0..570e441 100644 --- a/pyplayready/main.py +++ b/pyplayready/main.py @@ -279,7 +279,7 @@ def export_device(ctx: click.Context, prd_path: Path, out_dir: Optional[Path] = if device.group_key: group_key_path = out_path / "zgpriv.dat" - group_key_path.write_bytes(device.group_key.dumps()) + group_key_path.write_bytes(device.group_key.dumps(private_only=True)) log.info("Exported Group Key as zgpriv.dat") else: log.warning("Cannot export zgpriv.dat, as v2 devices do not save the group key") diff --git a/pyproject.toml b/pyproject.toml index 054b564..6251d18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pyplayready" -version = "0.4.2" +version = "0.4.3" description = "pyplayready CDM (Content Decryption Module) implementation in Python." license = "CC BY-NC-ND 4.0" authors = ["DevLARLEY, Erevoc", "DevataDev"]