diff --git a/pywidevine/L3/cdm/cdm.py b/pywidevine/L3/cdm/cdm.py index a565e98..ad55027 100644 --- a/pywidevine/L3/cdm/cdm.py +++ b/pywidevine/L3/cdm/cdm.py @@ -7,9 +7,9 @@ import binascii from google.protobuf.message import DecodeError from google.protobuf import text_format -from pywidevine.L3.cdm.formats import wv_proto2_pb2 as wv_proto2 -from pywidevine.L3.cdm.session import Session -from pywidevine.L3.cdm.key import Key +from pywidevineb.L3.cdm.formats import wv_proto2_pb2 as wv_proto2 +from pywidevineb.L3.cdm.session import Session +from pywidevineb.L3.cdm.key import Key from Cryptodome.Random import get_random_bytes from Cryptodome.Random import random from Cryptodome.Cipher import PKCS1_OAEP, AES @@ -19,18 +19,19 @@ from Cryptodome.Signature import pss from Cryptodome.Util import Padding import logging + class Cdm: def __init__(self): self.logger = logging.getLogger(__name__) self.sessions = {} - def open_session(self, init_data_b64, device, raw_init_data = None, offline=False): + def open_session(self, init_data_b64, device, raw_init_data=None, offline=False): self.logger.debug("open_session(init_data_b64={}, device={}".format(init_data_b64, device)) self.logger.info("opening new cdm session") if device.session_id_type == 'android': # format: 16 random hexdigits, 2 digit counter, 14 0s rand_ascii = ''.join(random.choice('ABCDEF0123456789') for _ in range(16)) - counter = '01' # this resets regularly so its fine to use 01 + counter = '01' # this resets regularly so its fine to use 01 rest = '00000000000000' session_id = rand_ascii + counter + rest session_id = session_id.encode('ascii') @@ -145,37 +146,32 @@ class Cdm: else: license_request = wv_proto2.SignedLicenseRequest() client_id = wv_proto2.ClientIdentification() - - if not os.path.exists(session.device_config.device_client_id_blob_filename): - self.logger.error("no client ID blob available for this device") + try: + cid_bytes = client_id.ParseFromString(base64.b64decode( + "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")) + except DecodeError: + self.logger.error("client id failed to parse as protobuf") return 1 - with open(session.device_config.device_client_id_blob_filename, "rb") as f: - try: - cid_bytes = client_id.ParseFromString(f.read()) - except DecodeError: - self.logger.error("client id failed to parse as protobuf") - return 1 - self.logger.debug("building license request") if not self.raw_pssh: license_request.Type = wv_proto2.SignedLicenseRequest.MessageType.Value('LICENSE_REQUEST') license_request.Msg.ContentId.CencId.Pssh.CopyFrom(session.init_data) else: license_request.Type = wv_proto2.SignedLicenseRequestRaw.MessageType.Value('LICENSE_REQUEST') - license_request.Msg.ContentId.CencId.Pssh = session.init_data # bytes + license_request.Msg.ContentId.CencId.Pssh = session.init_data # bytes if session.offline: - license_type = wv_proto2.LicenseType.Value('OFFLINE') + license_type = wv_proto2.LicenseType.Value('OFFLINE') else: - license_type = wv_proto2.LicenseType.Value('DEFAULT') + license_type = wv_proto2.LicenseType.Value('DEFAULT') license_request.Msg.ContentId.CencId.LicenseType = license_type license_request.Msg.ContentId.CencId.RequestId = session_id license_request.Msg.Type = wv_proto2.LicenseRequest.RequestType.Value('NEW') license_request.Msg.RequestTime = int(time.time()) license_request.Msg.ProtocolVersion = wv_proto2.ProtocolVersion.Value('CURRENT') if session.device_config.send_key_control_nonce: - license_request.Msg.KeyControlNonce = random.randrange(1, 2**31) + license_request.Msg.KeyControlNonce = random.randrange(1, 2 ** 31) if session.privacy_mode: if session.device_config.vmp: @@ -218,12 +214,40 @@ class Cdm: else: license_request.Msg.ClientId.CopyFrom(client_id) + kes="""-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAosIRKPWQ6+vptCMzSpZ4b4v5g8kp+qs2BgOepFOJG6Tuj1Ph +MzsK2ykmygErTW2X9PF610gjmCREslYzbcVdJ99+BAI1Yp18fFJCoOqYRUrs0mcb +1GaVuhU+hlml2AE8jOvHl/33fJir4Cws14/y680MGOJYPtHtYnvFrMUmMAReqlLs +HMvyMdGLR3oSOS35+xnh1Kuztrlw/KVlGSANFQ0bYMQEy6C4jC4aFu9IUMj+UPcG +pJ07t8cCPXh7eE1zb3SJuYvFqZKMT7OnethnaiDAE4xqQws5z6Wjrxmgop/Oz8hO +048G/jrNoDnfBK2nsWT+4EbuwFZTWsK28WyEdwIDAQABAoIBACkwyDr/ev/aIrlO +N0rnLe+9ExbBMHiaIAABpoKcCZUPdribV+EpTiQNFB4Hkbf0xoJdIuOdBDUa6K/h +lP5w9pSCwVeuX2hnxvuHrgkflg3jWnAdXDOzCq2fdsV1pr02Aub/PPJAegP0d3sy +ct7TNX1r1WXu0rqDUnqcLHj/JBz+drkyfcLOLbKffd98t1Sxsjy/aFMiUngHk/uj +imNamAMNhmob2xyah8pqg7Y7XFuZn3Wu+i+tL2HoAZRUaRWXiBPV1SST0F/4pQg5 +we9xaMfuxuwBIdRPkiiyagK1IWqT2XsVG2byMEvcq3iIVyAS1dzb85tZbdv+ufR4 +VoZ70lECgYEA1CvxfdmuqBG45GKQzin5+jnkGLnj6LjEH5EtUQPy2Is3N6WJIp6B +SHxgddoJZh3Pc9D62nKLTrAkkk1UpCrrFXpjy7VkIUBnEzVj0Nbh0xoV9brRPQOD +lqtrfj1NQNNY8ZgWpILnJ9n26Gqjr2nkUlAsu3bPaz/VzffA/waP4pUCgYEAxGEJ +MO99eIpkZdZU7PxjRs8rJmIzx77MekWpUJKtKzDA6BbwWI2oLuG9zbcANMKMdonD +j2ZXdVUQfqBvcwHuDmK+7FhKQ1Rw0jWWlrEADYQgK3MfqMPoOGv9Wn3hrBetSbWK +HTXOQQccDaEzSSCTOG3RPrMi2eIp7uFCENbqM9sCgYB4mdHW+1kv54L1LqGozmtt +NGLXOzK1IfE5EEh1+IydUeS9GLbumrJaBXi/BIS7Ks60wmEUsm9E9xKSpqop9stR +lhQLwrt7uyPb40kteDc8y2MYHmy5BbpSdnXPeADljDzOdujH8jB6koaqbZNFLie+ +Mhx7InmcONjLDr0BOTWoUQKBgQCAzkzjBhK8P7m+eijWEG1lgnkBAiSIfYNNJ+f4 +a1yeGapOEM2wp6mKppKCHehKstjC33Wf1zbCRPs+syimvLtSQD6OcxKyuu4NUwzk +5k/sjZ80IJzBa04jw+E3u52L7TPCRwrCQgp46Jrj7bnf2zf1KUK353OSih+LCcD1 +nqGbRQKBgQDC5ns0X8TnJCgf1BD3cGvc3o9zo3gw/NuZ6cqm8q45u0kiw5pRs+7j +9CXENirhHL5JXighOFB78Q3WWMuppTDxj7S1rpYdgp6+ITGSOmY5Xs6uaimilt2H +JPmXCYQt2Qu51bJ+MqZRWYeyN01O6rdKX/zGD9UTN5D3Ty3KEzogkg== +-----END RSA PRIVATE KEY-----""" + if session.device_config.private_key_available: - key = RSA.importKey(open(session.device_config.device_private_key_filename).read()) - session.device_key = key + key = RSA.importKey(kes) + session.device_key = key else: - self.logger.error("need device private key, other methods unimplemented") - return 1 + self.logger.error("need device private key, other methods unimplemented") + return 1 self.logger.debug("signing license request") @@ -318,7 +342,8 @@ class Cdm: lic_hmac = HMAC.new(session.derived_keys['auth_1'], digestmod=SHA256) lic_hmac.update(license.Msg.SerializeToString()) - self.logger.debug("calculated sig: {} actual sig: {}".format(lic_hmac.hexdigest(), binascii.hexlify(license.Signature))) + self.logger.debug( + "calculated sig: {} actual sig: {}".format(lic_hmac.hexdigest(), binascii.hexlify(license.Signature))) if lic_hmac.digest() != license.Signature: self.logger.info("license signature doesn't match - writing bin so they can be debugged")