parent
4ea1fbd1f8
commit
c910d1f349
|
@ -10,4 +10,4 @@ from .session import *
|
|||
from .xml_key import *
|
||||
from .xmrlicense import *
|
||||
|
||||
__version__ = "0.4.2"
|
||||
__version__ = "0.4.3"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"]
|
||||
|
|
Loading…
Reference in New Issue