From 862d8d4a9a1e2ee2783be0703f4c7b949c2c1b4b Mon Sep 17 00:00:00 2001 From: dropcodes <97192664+dropcreations@users.noreply.github.com> Date: Thu, 9 Nov 2023 19:25:47 +0530 Subject: [PATCH] Updated. --- core/__init__.py | 1 + core/api/__init__.py | 1 + core/api/album.py | 130 + core/api/aplm.py | 392 +++ core/api/artist.py | 89 + core/api/lyrics.py | 45 + core/api/musicvideo.py | 41 + core/content/__init__.py | 3 + core/content/animartwork.py | 50 + core/content/audio.py | 48 + core/content/video.py | 48 + core/control.py | 427 +++ core/parse.py | 128 + core/process/__init__.py | 3 + core/process/download.py | 39 + core/process/process.py | 86 + core/process/tagger.py | 85 + manzana.py | 88 + utils/__init__.py | 3 + utils/cache.py | 33 + utils/config.py | 136 + utils/keys.py | 63 + utils/logger.py | 84 + utils/stats.py | 37 + utils/widevine/__init__.py | 3 + utils/widevine/cdm.py | 319 ++ .../widevine/formats/widevine_pssh_data.proto | 56 + .../formats/widevine_pssh_data_pb2.py | 46 + utils/widevine/formats/wv_proto2.proto | 466 +++ utils/widevine/formats/wv_proto2_pb2.py | 147 + utils/widevine/formats/wv_proto3.proto | 389 +++ utils/widevine/formats/wv_proto3_pb2.py | 2684 +++++++++++++++++ utils/widevine/widevine.py | 61 + 33 files changed, 6231 insertions(+) create mode 100644 core/__init__.py create mode 100644 core/api/__init__.py create mode 100644 core/api/album.py create mode 100644 core/api/aplm.py create mode 100644 core/api/artist.py create mode 100644 core/api/lyrics.py create mode 100644 core/api/musicvideo.py create mode 100644 core/content/__init__.py create mode 100644 core/content/animartwork.py create mode 100644 core/content/audio.py create mode 100644 core/content/video.py create mode 100644 core/control.py create mode 100644 core/parse.py create mode 100644 core/process/__init__.py create mode 100644 core/process/download.py create mode 100644 core/process/process.py create mode 100644 core/process/tagger.py create mode 100644 manzana.py create mode 100644 utils/__init__.py create mode 100644 utils/cache.py create mode 100644 utils/config.py create mode 100644 utils/keys.py create mode 100644 utils/logger.py create mode 100644 utils/stats.py create mode 100644 utils/widevine/__init__.py create mode 100644 utils/widevine/cdm.py create mode 100644 utils/widevine/formats/widevine_pssh_data.proto create mode 100644 utils/widevine/formats/widevine_pssh_data_pb2.py create mode 100644 utils/widevine/formats/wv_proto2.proto create mode 100644 utils/widevine/formats/wv_proto2_pb2.py create mode 100644 utils/widevine/formats/wv_proto3.proto create mode 100644 utils/widevine/formats/wv_proto3_pb2.py create mode 100644 utils/widevine/widevine.py diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..0c4d744 --- /dev/null +++ b/core/__init__.py @@ -0,0 +1 @@ +from core.control import run \ No newline at end of file diff --git a/core/api/__init__.py b/core/api/__init__.py new file mode 100644 index 0000000..712f9fd --- /dev/null +++ b/core/api/__init__.py @@ -0,0 +1 @@ +from core.api.aplm import AppleMusic \ No newline at end of file diff --git a/core/api/album.py b/core/api/album.py new file mode 100644 index 0000000..8a00f03 --- /dev/null +++ b/core/api/album.py @@ -0,0 +1,130 @@ +import m3u8 +from core import parse + +from . import lyrics + +def parse_data(data): + media = {} + media_list = [] + + attr = data["attributes"] + + media["coverUrl"] = attr["artwork"]["url"].format( + w=attr["artwork"].get("width"), + h=attr["artwork"].get("height") + ) + + if "editorialVideo" in attr: + if "motionDetailSquare" in attr["editorialVideo"]: + __data = m3u8.load( + attr["editorialVideo"]["motionDetailSquare"].get("video") + ) + + streamList = [] + + for i, variants in enumerate(__data.playlists): + streamList.append( + { + "id": i, + "fps": variants.stream_info.frame_rate, + "codec": "AVC" if "avc" in variants.stream_info.codecs else "HEVC", + "range": variants.stream_info.video_range, + "bitrate": f'{round((variants.stream_info.average_bandwidth)/1000000, 2)} Mb/s', + "resolution": f'{variants.stream_info.resolution[0]}x{variants.stream_info.resolution[1]}', + "uri": variants.uri + } + ) + + media["animartwork"] = streamList + + dirname = parse.sanitize( + "{} - {} [{}]{}{}{}".format( + attr.get("artistName"), + attr.get("name"), + data["id"], + " [S]" if "Single" in attr.get("name") else "", + " [EP]" if "EP" in attr.get("name") else "", + " [E]" if attr.get("contentRating") == "explicit" else "" + ) + ) + + media["dir"] = dirname.replace(' - Single', '').replace(' - EP', '') + + a = { + "copyright": attr.get("copyright"), + "upc": attr.get("upc"), + "recordlabel": attr.get("recordLabel"), + "trackcount": attr.get("trackCount"), + "album": attr.get("name"), + "albumartist": attr.get("artistName") + } + + for item in data["relationships"]["tracks"]["data"]: + attr = item.get("attributes") + + filename = parse.sanitize( + "{} - {}{}".format( + str(attr.get("trackNumber")).zfill(2), + attr.get("name"), + " [E]" if attr.get("contentRating") == "explicit" else "" + ) + ) + + s = { + "id": item.get("id"), + "genre": attr.get("genreNames"), + "releasedate": attr.get("releaseDate"), + "trackno": attr.get("trackNumber"), + "isrc": attr.get("isrc"), + "composer": attr.get("composerName"), + "discno": attr.get("discNumber"), + "song": attr.get("name"), + "songartist": attr.get("artistName"), + "rating": 4 if attr.get("contentRating") == "explicit" else 0, + "file": filename + } + + rela = item.get("relationships") + if not rela: rela = {} + + if "credits" in rela: + credits = rela["credits"].get("data") + if credits: + + roles = [] + creds = {} + + for catagory in credits: + for credit in catagory["relationships"]["credit-artists"]["data"]: + for role in credit["attributes"]["roleNames"]: + if not role in roles: + roles.append(role) + creds[role] = [credit["attributes"]["name"]] + else: + roleArtist: list = creds[role] + roleArtist.append(credit["attributes"]["name"]) + creds[role] = roleArtist + + s["credits"] = creds + + if "lyrics" in rela: + if rela["lyrics"].get("data"): + if rela["lyrics"]["data"][0].get("attributes"): + s.update( + lyrics.parse( + rela["lyrics"]["data"][0]["attributes"]["ttml"] + ) + ) + + if item.get("type") == "songs": + s["type"] = 1 + elif item.get("type") == "music-videos": + s["type"] = 6 + + s.update(a) + media_list.append( + parse.opt(s) + ) + + media["tracks"] = media_list + return media \ No newline at end of file diff --git a/core/api/aplm.py b/core/api/aplm.py new file mode 100644 index 0000000..ac87da9 --- /dev/null +++ b/core/api/aplm.py @@ -0,0 +1,392 @@ +import re +import json +import requests + +from bs4 import BeautifulSoup +from urllib.parse import urlparse +from base64 import b64decode, b64encode +from rich.console import Console + +from core import parse +from utils import logger +from utils import cache +from utils import keys +from utils import config +from utils import Widevine +from utils import WidevinePsshData + +from . import artist +from . import album +from . import musicvideo + +cons = Console() + +class AppleMusic: + def __init__(self): + self.session = requests.Session() + self.session.headers = { + 'connection': 'keep-alive', + 'accept': 'application/json', + 'origin': 'https://music.apple.com', + 'referer': 'https://music.apple.com/', + 'accept-encoding': 'gzip, deflate, br', + 'content-type': 'application/json;charset=utf-8', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36' + } + + self.__check_access_token() + self.__check_media_user_token() + + def __parse_url(self, url): + logger.debug("Parsing url...") + + self.songId = None + u = urlparse(url) + + if not u.scheme: + url = f"https://{url}" + + if u.netloc == "music.apple.com": + s = u.path.split('/') + self.kind = s[2] + self.id = s[-1] + if u.query: + self.songId = u.query.replace('i=', '') + + logger.debug(f'UrlParseResult(kind="{self.kind}", id="{self.id}", songId="{self.songId}")') + else: + logger.error("Url is invalid!", 1) + + def __check_access_token(self): + def get_access_token(): + logger.info("Fetching accessToken from web...") + r = requests.get('https://music.apple.com/us/browse') + c = BeautifulSoup(r.text, "html.parser") + js = c.find( + "script", + attrs={ + 'type': 'module', + 'crossorigin': True, + 'src': True + } + ).get('src') + r = requests.get(f'https://music.apple.com{js}') + at = re.search('(?=eyJh)(.*?)(?=")', r.text).group(1) + logger.debug(f'access-token: {at}') + return at + + at = config.get('accessToken') + if at: + logger.info("Checking accessToken...") + self.session.headers['authorization'] = f'Bearer {at}' + r = self.session.get("https://amp-api.music.apple.com/v1/catalog/us/songs/1450330685") + if r.text == "": + logger.error("accessToken is expired!") + at = get_access_token() + self.session.headers['authorization'] = f'Bearer {at}' + config.set('accessToken', at) + else: logger.debug(f'accessToken is working! access-token: {at}') + else: + at = get_access_token() + self.session.headers['authorization'] = f'Bearer {at}' + config.set('accessToken', at) + + def __check_media_user_token(self): + mut = config.get('mediaUserToken') + logger.info("Checking mediaUserToken...") + self.session.headers['media-user-token'] = mut + r = self.session.get("https://amp-api.music.apple.com/v1/me/storefront") + + if r.status_code == 200: + r = json.loads(r.text) + self.storefront = r["data"][0]["id"] + self.language = r["data"][0]["attributes"]["defaultLanguageTag"] + logger.debug(f"mediaUserToken is working! mediaUserToken: {mut}") + self.session.headers['accept-language'] = f'{self.language},en;q=0.9' + else: + logger.error("Your mediaUserToken is invalid! Enter again to continue...") + config.delete('mediaUserToken') + mut = input("\n\tmediaUserToken: "); print() + config.set('mediaUserToken', mut) + self.__check_media_user_token() + + def __get_artist(self, url): + def __get_res(session, apiUrl): + urls = [] + + while True: + r = session.get(apiUrl) + r = json.loads(r.text) + + for item in r["data"]: + name = item["attributes"]["name"] + if " - EP" in name: name = name.replace(" - EP", "") + " [EP]" + if " - Single" in name: name = name.replace(" - Single", "") + " [S]" + if item["attributes"].get("contentRating"): name += " [E]" + + urls.append( + { + "url": item["attributes"].get("url"), + "name": name, + "contentId": item["id"] + } + ) + + if "next" in r: + nextUrl = r["next"] + apiUrl = f'https://amp-api.music.apple.com/{nextUrl}' + else: + break + + return urls + + r = requests.get(url) + c = BeautifulSoup(r.text, "html.parser") + + name = c.find( + "meta", + attrs={ + 'name': 'apple:title', + 'content': True + } + ).get('content') + + id = c.find( + "meta", + attrs={ + 'name': 'apple:content_id', + 'content': True + } + ).get('content') + + logger.info(f"Fetching artist contents...") + cons.print(f'\n\t [dim]Artist:[/] {name}') + + return artist.get_urls( + __get_res( + self.session, + f"https://amp-api.music.apple.com/v1/catalog/{self.storefront}/artists/{id}/view/full-albums?limit=100" + ), + __get_res( + self.session, + f"https://amp-api.music.apple.com/v1/catalog/{self.storefront}/artists/{id}/view/singles?limit=100" + ), + __get_res( + self.session, + f"https://amp-api.music.apple.com/v1/catalog/{self.storefront}/artists/{id}/view/music-videos?limit=100" + ), + name + ) + + def __get_api(self): + logger.info("Fetching API response...") + params = None + + if self.kind == "album": + params = { + 'extend': 'editorialVideo', + 'include[songs]': 'lyrics,credits' + } + + r = self.session.get( + f"https://amp-api.music.apple.com/v1/catalog/{self.storefront}/{self.kind}s/{self.id}?l={self.language}", + params=params + ) + + if r.status_code != 200: + logger.error(f"[{r.status_code}] {r.reason}: {r.content}", 1) + r = json.loads(r.text) + + if not "errors" in r: + return r + else: + errors = r["errors"] + if not isinstance(errors, list): errors = [errors] + for error in errors: + logger.error( + "{err_status}: {err_detail}".format( + err_status=error.get("status"), + err_details=error.get("detail") + ) + ) + exit(1) + + def __get_info(self): + data = cache.get(self.id) + if data: + logger.info("Using data found in cache...") + return data + + if self.kind == "album": + data = album.parse_data( + self.__get_api()["data"][0] + ) + elif self.kind == "music-video": + data = musicvideo.parse_data( + self.__get_api()["data"][0] + ) + + cache.set(self.id, data) + return data + + def __get_webplayback(self, id): + logger.info("Getting webplayback...") + + r = self.session.post( + url="https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/webPlayback", + data=json.dumps({'salableAdamId': id}) + ) + + if r.status_code != 200: + logger.error(f"[{r.status_code}] {r.reason}: {r.content}", 1) + r = json.loads(r.text) + + if not "failureType" in r: + return r["songList"][0] + else: + er = r.get("customerMessage") + if er: logger.error(er) + else: logger.error("Unable to get webplayback!") + + def __get_license(self, assetId, keyUri, challenge="CAQ="): + r = self.session.post( + url=self.licenseUrl, + data=json.dumps( + { + "adamId": assetId, + "challenge": challenge, + "isLibrary": False, + "key-system": "com.widevine.alpha", + "uri": keyUri, + "user-initiated": True + } + ) + ) + + if r.status_code != 200: + logger.error(f"[{r.status_code}] {r.reason}: {r.content}", 1) + + r = json.loads(r.text) + if not "license" in r: + logger.error("Unable to get license!", 1) + return r.get("license") + + def __get_song_keys(self, songId, keyUri): + cert_data_b64 = self.__get_license(songId, keyUri) + + dataPSSH = WidevinePsshData() + dataPSSH.algorithm = 1 + dataPSSH.key_id.append(b64decode(keyUri.split(",")[1])) + + pssh = b64encode(dataPSSH.SerializeToString()).decode("utf8") + + widevine = Widevine( + init_data=pssh, + cert_data=cert_data_b64, + device_name=config.get('deviceName'), + device_path=config.get('devicePath') + ) + + license = self.__get_license( + songId, keyUri, + b64encode( + widevine.get_challenge() + ).decode("utf-8") + ) + + widevine.update_license(license) + return widevine.get_keys() + + def __get_musicvideo_keys(self, musicVideoId, keyUri): + cert_data_b64 = self.__get_license(musicVideoId, keyUri) + + widevine = Widevine( + init_data=keyUri.split(",")[-1], + cert_data=cert_data_b64, + device_name=config.get('deviceName'), + device_path=config.get('devicePath') + ) + + license = self.__get_license( + musicVideoId, keyUri, + b64encode( + widevine.get_challenge() + ).decode("utf-8") + ) + + widevine.update_license(license) + return widevine.get_keys() + + def get_urls(self, urls: list): + u = [] + for url in urls: + if "/artist/" in url: + self.__parse_url(url) + for ul in self.__get_artist(url): + u.append(ul) + else: u.append(url) + return u + + def get_info(self, url): + self.__parse_url(url) + return [self.__get_info()] + + def get_content(self, data): + id = data.get("id") + + wp = self.__get_webplayback(id) + if not wp: wp = {} + + self.licenseUrl = wp.get("hls-key-server-url") + + if "hls-playlist-url" in wp: + assetUrl = wp["hls-playlist-url"] + logger.info("Parsing music-video uri...") + streams = parse.mv_uri(assetUrl) + psshs = parse.mv_psshs(streams) + + for pssh in psshs: + logger.info("Checking decrypt keys...") + dec_key = keys.get(pssh) + + if not dec_key: + logger.info("Requesting decrypt keys...") + dec_key = self.__get_musicvideo_keys(id, f'data:text/plain;base64,{pssh}') + if dec_key: + logger.info("Saving decrypt keys...") + keys.set(pssh, dec_key) + else: logger.warning("Unable to get decrypt keys!") + else: logger.info("Using decrypt keys found in vault...") + + data["streams"] = streams + + elif "assets" in wp: + asset = next((asset for asset in wp["assets"] if asset["flavor"] == "28:ctrp256"), None) + if not asset: logger.error("Failed to find 28:ctrp256 asset!") + + assetUrl = asset.get("URL") + metadata = asset.get("metadata") + + if "discCount" in metadata: + data["disccount"] = metadata.get("discCount") + + logger.info("Parsing song uri...") + stream = parse.aud_uri(assetUrl) + + pssh = stream["pssh"] + logger.info("Checking decrypt keys...") + key = keys.get(pssh) + + if not key: + logger.info("Requesting decrypt keys...") + key = self.__get_song_keys(id, f'data:;base64,{pssh}') + logger.info("Saving decrypt keys...") + keys.set(pssh, key) + else: logger.info("Using decrypt key found in vault...") + + data["streams"] = stream + + else: + data["streams"] = False + return False + return True \ No newline at end of file diff --git a/core/api/artist.py b/core/api/artist.py new file mode 100644 index 0000000..45f4c4e --- /dev/null +++ b/core/api/artist.py @@ -0,0 +1,89 @@ +from rich import box +from rich.table import Table +from rich.console import Console +from rich.columns import Columns + +from utils import logger + +console = Console() + +def __user(contents: list): + ids = [] + table = Table(box=box.ROUNDED) + + table.add_column("ID", justify="center") + table.add_column("Name", justify="left") + table.add_column("ContentID", justify="left") + + for i, content in enumerate(contents): + ids.append(i) + table.add_row( + str(i), + content.get("name"), + content.get("contentId") + ) + + print() + columns = Columns([" ", table]) + console.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + elif id == "all": return [url.get("url") for url in contents] + else: + try: id = [int(i.strip()) for i in id.split(',')] + except: logger.error("Input is invalid!", 1) + id = list(set(id)) + + returnContent = [] + + for i in id: + if i in ids: returnContent.append(contents[i]["url"]) + else: logger.warning(f'ID: {i} not in the list!') + + return returnContent + +def get_urls(a, s, m, name): + table = Table( + box=box.ROUNDED + ) + + table.add_column("ID", justify="center") + table.add_column("Kind", justify="center") + table.add_column("Count", justify="center") + + table.add_row('0', 'albums', str(len(a))) + table.add_row('1', 'singles', str(len(s))) + table.add_row('2', 'music-videos', str(len(m))) + + print() + columns = Columns([" ", table]) + console.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + elif id == "all": id = [0, 1, 2] + else: + try: id = [int(id.strip()) for id in id.split(',')] + except: logger.error("Input is invalid!", 1) + id = list(set(id)) + + contents = [] + + for i in id: + if i in [0, 1, 2]: + if i == 0: + logger.info(f"Getting {name}'s full-albums...") + contents += __user(a) + elif i == 1: + logger.info(f"Getting {name}'s singles...") + contents += __user(s) + else: + logger.info(f"Getting {name}'s music-videos...") + contents += __user(m) + else: + logger.warning(f'ID: {i} not in the list!') + + return contents \ No newline at end of file diff --git a/core/api/lyrics.py b/core/api/lyrics.py new file mode 100644 index 0000000..9551606 --- /dev/null +++ b/core/api/lyrics.py @@ -0,0 +1,45 @@ +from bs4 import BeautifulSoup + +def __get_ts(ts): + ts = str(ts).replace('s', '') + secs = float(ts.split(':')[-1]) + + if ":" in ts: + mins = ts.split(':')[-2] + else: + mins = int(str(secs / 60)[:1]) + secs = float(str(secs % 60)) + + return f'{mins:0>2}:{secs:05.2f}' + +def parse(ttml): + ttml = BeautifulSoup(ttml, "lxml") + + lyrics = [] + songwriters = [] + timeSyncedLyrics = [] + + songwriter = ttml.find_all("songwriter") + + if len(songwriter) > 0: + for sw in songwriter: + songwriters.append(sw.text) + + for line in ttml.find_all("p"): + lyrics.append(line.text) + + if "span" in str(line): + span = BeautifulSoup(str(line), "lxml") + + for s in span.find_all("span", attrs={'begin': True, 'end': True}): + begin = __get_ts(s.get("begin")) + timeSyncedLyrics.append(f"[{begin}]{s.text}") + else: + begin = __get_ts(line.get("begin")) + timeSyncedLyrics.append(f"[{begin}]{line.text}") + + return { + "lyrics": lyrics, + "songwriter": songwriters if len(songwriters) > 0 else None, + "timeSyncedLyrics": timeSyncedLyrics + } \ No newline at end of file diff --git a/core/api/musicvideo.py b/core/api/musicvideo.py new file mode 100644 index 0000000..b70e544 --- /dev/null +++ b/core/api/musicvideo.py @@ -0,0 +1,41 @@ +from core import parse + +def parse_data(data): + media = {} + media_list = [] + + attr = data["attributes"] + + media["coverUrl"] = attr["artwork"]["url"].format( + w=attr["artwork"].get("width"), + h=attr["artwork"].get("height") + ) + + filename = parse.sanitize( + "{} - {} [{}]{}".format( + attr.get("artistName"), + attr.get("name"), + data.get("id"), + " [E]" if attr.get("contentRating") == "explicit" else "" + ) + ) + + s = { + "id": data.get("id"), + "type": 6, + "genre": attr.get("genreNames"), + "releasedate": attr.get("releaseDate"), + "isrc": attr.get("isrc"), + "song": attr.get("name"), + "songartist": attr.get("artistName"), + "rating": 4 if attr.get("contentRating") == "explicit" else 0, + "file": filename, + "dir": "no_dir", + } + + media_list.append( + parse.opt(s) + ) + + media["tracks"] = media_list + return media \ No newline at end of file diff --git a/core/content/__init__.py b/core/content/__init__.py new file mode 100644 index 0000000..73e3b10 --- /dev/null +++ b/core/content/__init__.py @@ -0,0 +1,3 @@ +from core.content.animartwork import get_animartwork +from core.content.audio import get_audio +from core.content.video import get_video \ No newline at end of file diff --git a/core/content/animartwork.py b/core/content/animartwork.py new file mode 100644 index 0000000..0a255b0 --- /dev/null +++ b/core/content/animartwork.py @@ -0,0 +1,50 @@ +from rich import box +from rich.table import Table +from rich.console import Console +from rich.columns import Columns + +from utils import logger + +console = Console() + +def get_animartwork(data): + if "animartwork" in data: + logger.info("Getting animated artwork variants...") + + ids = [] + streamList = data.get("animartwork") + + table = Table(box=box.ROUNDED) + + table.add_column("ID", justify="center") + table.add_column("Codec", justify="left") + table.add_column("Bitrate", justify="left") + table.add_column("Resolution", justify="left") + table.add_column("FPS", justify="center") + table.add_column("Range", justify="center") + + for i, stream in enumerate(streamList): + ids.append(i) + table.add_row( + str(i), + stream.get("codec"), + stream.get("bitrate"), + stream.get("resolution"), + str(stream.get("fps")), + stream.get("range") + ) + + print() + columns = Columns([" ", table]) + console.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + else: + try: id = int(id) + except: logger.error("Invalid input!", 1) + + if id in ids: return streamList[id] + else: logger.error("ID not found in the list!", 1) + else: logger.error("No animated artworks available!") \ No newline at end of file diff --git a/core/content/audio.py b/core/content/audio.py new file mode 100644 index 0000000..061cc7a --- /dev/null +++ b/core/content/audio.py @@ -0,0 +1,48 @@ +from rich import box +from rich.table import Table +from rich.console import Console +from rich.columns import Columns + +from utils import logger + +console = Console() + +def get_audio(streams): + logger.info("Getting audio streams list...") + + ids = [] + streamList = [s for s in streams if s['type'] == 'audio'] + + table = Table(box=box.ROUNDED) + + table.add_column("ID", justify="center") + table.add_column("Codec", justify="center") + table.add_column("Bitrate", justify="left") + table.add_column("Channels", justify="center") + table.add_column("Name", justify="center") + table.add_column("Language", justify="center") + + for i, stream in enumerate(streamList): + ids.append(i) + table.add_row( + str(i), + stream.get("codec"), + stream.get("bitrate"), + str(stream.get("channels")), + stream.get("name"), + stream.get("language") + ) + + print() + columns = Columns([" ", table]) + console.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + else: + try: id = int(id) + except: logger.error("Invalid input!", 1) + + if id in ids: return streamList[id] + else: logger.error("ID not found in the list!", 1) \ No newline at end of file diff --git a/core/content/video.py b/core/content/video.py new file mode 100644 index 0000000..e37c22e --- /dev/null +++ b/core/content/video.py @@ -0,0 +1,48 @@ +from rich import box +from rich.table import Table +from rich.console import Console +from rich.columns import Columns + +from utils import logger + +console = Console() + +def get_video(streams): + logger.info("Getting video streams list...") + + ids = [] + streamList = [s for s in streams if s['type'] == 'video'] + + table = Table(box=box.ROUNDED) + + table.add_column("ID", justify="center") + table.add_column("Codec", justify="left") + table.add_column("Bitrate", justify="left") + table.add_column("Resolution", justify="left") + table.add_column("FPS", justify="center") + table.add_column("Range", justify="center") + + for i, stream in enumerate(streamList): + ids.append(i) + table.add_row( + str(i), + stream.get("codec"), + stream.get("bitrate"), + stream.get("resolution"), + str(stream.get("fps")), + stream.get("range") + ) + + print() + columns = Columns([" ", table]) + console.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + else: + try: id = int(id) + except: logger.error("Invalid input!", 1) + + if id in ids: return streamList[id] + else: logger.error("ID not found in the list!", 1) \ No newline at end of file diff --git a/core/control.py b/core/control.py new file mode 100644 index 0000000..0b3bfd2 --- /dev/null +++ b/core/control.py @@ -0,0 +1,427 @@ +import os +import m3u8 +import requests + +from rich.console import Console + +from core import parse +from core.api import AppleMusic + +from core.process import download +from core.process import decrypt +from core.process import muxhls +from core.process import muxmv +from core.process import tag +from core.process import cc + +from core.content import get_video +from core.content import get_audio +from core.content import get_animartwork + +from utils import logger +from utils import keys +from utils import stats +from utils.stats import TEMPDIR +from utils.stats import OUTPUTDIR + +cons = Console() + +def run(args): + try: + aplm = AppleMusic() + logger.info("Checking passed urls...") + + urls = parse.input_urls(args.url) + urls = aplm.get_urls(urls) + + logger.info("Starting download process...") + + for url in urls: + cons.print(f"\n\t[italic bold]URL: {url}[/]\n") + data = aplm.get_info(url) + + for sub_data in data: + dn = sub_data.get("dir") + if not dn: dn = "" + + out_dir = os.path.join(OUTPUTDIR, dn) + os.makedirs(out_dir, exist_ok=True) + cover_data = requests.get(sub_data.get("coverUrl"), stream=True).content + + if args.anim: + __anh_fp = os.path.join( + TEMPDIR, + "hlsCover.mp4" + ) + + __ano_fp = os.path.join( + out_dir, + "Cover.mp4" + ) + + if not os.path.exists(__ano_fp): + anim = get_animartwork(sub_data) + if anim: + uri = m3u8.load(anim.get("uri")) + uri = uri.base_uri + uri.segment_map[0].uri + + logger.info(f'Downloading "{anim["resolution"]}" artwork...') + download(uri, __anh_fp) + + logger.info("Muxing animated artwork...") + rt = muxhls(__anh_fp, __ano_fp) + if rt == 0: + os.remove(__anh_fp) + else: logger.error("Muxing failed!") + else: + logger.info("Cover animation is already exists! skipping...") + + for track in sub_data["tracks"]: + if aplm.songId: + if track["id"] != aplm.songId: + continue + + cons.print(f"[dim]{'-'*35}[/]") + + if track["type"] == 1: + __enc_fp = os.path.join( + TEMPDIR, + "enc_aud_{}.mp4".format( + track["id"] + ) + ) + + __dec_fp = os.path.join( + TEMPDIR, + "dec_aud_{}.mp4".format( + track["id"] + ) + ) + + __mux_fp = os.path.join( + TEMPDIR, + "mux_aud_{}.m4a".format( + track["id"] + ) + ) + + __out_fp = os.path.join( + out_dir, + f'{track["file"]}.m4a' + ) + + if os.path.exists(__out_fp): + logger.info(f'"{track["file"]}.m4a" is already exists! skipping...') + continue + + else: + __enc_v_fp = os.path.join( + TEMPDIR, + "enc_mv_vid_{}.mp4".format( + track["id"] + ) + ) + + __enc_a_fp = os.path.join( + TEMPDIR, + "enc_mv_aud_{}.mp4".format( + track["id"] + ) + ) + + __dec_v_fp = os.path.join( + TEMPDIR, + "dec_mv_vid_{}.mp4".format( + track["id"] + ) + ) + + __dec_a_fp = os.path.join( + TEMPDIR, + "dec_mv_aud_{}.mp4".format( + track["id"] + ) + ) + + __sub_fp = os.path.join( + TEMPDIR, + "sub_mv_{}.srt".format( + track["id"] + ) + ) + + __mux_fp = os.path.join( + TEMPDIR, + "mux_mv_{}.mp4".format( + track["id"] + ) + ) + + __out_fp = os.path.join( + out_dir, + f'{track["file"]}.mp4' + ) + + if args.skip: + if "album" in track: + logger.info(f'Skipping "{track["song"]}" music-video...') + continue + + if os.path.exists(__out_fp): + logger.info(f'"{track["file"]}.mp4" is already exists! skipping...') + continue + + gc = aplm.get_content(track) + if not gc: continue + + if track["type"] == 1: + st = stats.get(track["id"]) + if not st: + st = { + "isDownloaded": False, + "isDecrypted": False, + "isMuxed": False, + "isTagged": False + } + + if not st["isDownloaded"]: + if os.path.exists(__enc_fp): + os.remove(__enc_fp) + + logger.info(f'Downloading "{track["file"]}"...') + + download( + track["streams"]["uri"], + __enc_fp + ) + + st["isDownloaded"] = True + stats.set(track["id"], st) + else: logger.info("Audio is already downloaded!") + + if not st["isDecrypted"]: + if os.path.exists(__dec_fp): + os.remove(__dec_fp) + + logger.info("Decrypting audio...") + __ky = keys.get(track["streams"]["pssh"]) + + rt = decrypt( + __enc_fp, + __dec_fp, + __ky + ) + + if rt == 0: + st["isDecrypted"] = True + stats.set(track["id"], st) + os.remove(__enc_fp) + else: + logger.error("Decryption failed!", 1) + else: logger.info("Audio is already decrypted!") + + if not st["isMuxed"]: + if os.path.exists(__mux_fp): + os.remove(__mux_fp) + + logger.info("Muxing audio...") + + rt = muxhls( + __dec_fp, + __mux_fp + ) + + if rt == 0: + st["isMuxed"] = True + stats.set(track["id"], st) + os.remove(__dec_fp) + else: + logger.error("Muxing failed!", 1) + else: logger.info("Audio is already muxed!") + + if not args.noTags: + if not st["isTagged"]: + logger.info("Tagging audio...") + + tag( + __mux_fp, + track, + cover_data, + [OUTPUTDIR, out_dir], + args.noCover, + args.noLrc + ) + + st["isTagged"] = True + stats.set(track["id"], st) + else: logger.info("Audio is already tagged!") + + if os.path.exists(__mux_fp): + os.renames(__mux_fp, __out_fp) + + else: + st = stats.get(track["id"]) + if not st: + st = { + "isVideoDownloaded": False, + "isAudioDownloaded": False, + "isVideoDecrypted": False, + "isAudioDecrypted": False, + "isMuxed": False, + "isTagged": False, + "vt": None, + "at": None + } + + if st["vt"]: vt = st["vt"] + else: + vt = get_video(track.get("streams")) + st["vt"] = vt + stats.set(track["id"], st) + + + if not st["isVideoDownloaded"]: + if os.path.exists(__enc_v_fp): + os.remove(__enc_v_fp) + + logger.info(f'Downloading "{track["file"]}" video...') + + download( + vt["uri"], + __enc_v_fp + ) + + st["isVideoDownloaded"] = True + stats.set(track["id"], st) + else: logger.info("Music-video's video stream is already downloaded!") + + if not st["isVideoDecrypted"]: + if os.path.exists(__dec_v_fp): + os.remove(__dec_v_fp) + + logger.info("Decrypting video...") + __ky = keys.get(vt["pssh"]) + + rt = decrypt( + __enc_v_fp, + __dec_v_fp, + __ky + ) + + if rt == 0: + st["isVideoDecrypted"] = True + stats.set(track["id"], st) + os.remove(__enc_v_fp) + else: + logger.error("Decryption failed!", 1) + else: logger.info("Music-video's video stream is already decrypted!") + + if st["at"]: at = st["at"] + else: + at = get_audio(track.get("streams")) + st["at"] = at + stats.set(track["id"], st) + + if not st["isAudioDownloaded"]: + if os.path.exists(__enc_a_fp): + os.remove(__enc_a_fp) + + logger.info(f'Downloading "{track["file"]}" audio...') + + download( + at["uri"], + __enc_a_fp + ) + + st["isAudioDownloaded"] = True + stats.set(track["id"], st) + else: logger.info("Music-video's audio stream is already downloaded!") + + if not st["isAudioDecrypted"]: + if os.path.exists(__dec_a_fp): + os.remove(__dec_a_fp) + + logger.info("Decrypting audio...") + __ky = keys.get(at["pssh"]) + + rt = decrypt( + __enc_a_fp, + __dec_a_fp, + __ky + ) + + if rt == 0: + st["isAudioDecrypted"] = True + stats.set(track["id"], st) + os.remove(__enc_a_fp) + else: + logger.error("Decryption failed!", 1) + else: logger.info("Music-video's audio stream is already decrypted!") + + if not st["isMuxed"]: + if os.path.exists(__mux_fp): + os.remove(__mux_fp) + + logger.info("Extracting closed-captions...") + cc(__dec_v_fp, __sub_fp) + if os.path.getsize(__sub_fp) == 0: + logger.info("No closed-captions available!") + __sub_fp = None + + logger.info("Muxing music-video...") + rt = muxmv( + __dec_v_fp, + __dec_a_fp, + __mux_fp, + at, + __sub_fp + ) + + if rt == 0: + st["isMuxed"] = True + stats.set(track["id"], st) + os.remove(__dec_v_fp) + os.remove(__dec_a_fp) + if __sub_fp: + os.remove(__sub_fp) + else: + logger.error("Muxing failed!", 1) + else: logger.info("Music-video is already muxed!") + + if not args.noTags: + if not st["isTagged"]: + logger.info("Tagging music-video...") + + tag( + __mux_fp, + track, + cover_data, + [OUTPUTDIR, out_dir], + args.noCover, + args.noLrc + ) + + st["isTagged"] = True + stats.set(track["id"], st) + else: logger.info("Music-video is already tagged!") + + if os.path.exists(__mux_fp): + os.renames(__mux_fp, __out_fp) + + if not args.noCover: + if aplm.kind != "music-video": + with open(os.path.join(out_dir, 'Cover.jpg'), 'wb') as fp: + fp.write(cover_data) + + cons.print(f"[dim]{'-'*35}[/]") + + logger.info("Cleaning temp...") + for t in os.listdir(TEMPDIR): + os.remove( + os.path.join(TEMPDIR, t) + ) + + logger.info("Done.") + + except KeyboardInterrupt: + logger.error("Interrupted by user!") \ No newline at end of file diff --git a/core/parse.py b/core/parse.py new file mode 100644 index 0000000..222aa8c --- /dev/null +++ b/core/parse.py @@ -0,0 +1,128 @@ +import os +import m3u8 +import aiohttp +import asyncio +import unicodedata + +def sanitize(f): + b = ['\\', '/', ':', '*', '?', '"', '<', '>', '|', '\0'] + f = ''.join(c for c in f if c not in b) + f = ''.join(c for c in f if 31 < ord(c)) + f = unicodedata.normalize("NFKD", f) + f = f.rstrip(". ") + return f.strip() + +def opt(d: dict): + nd = {} + for k, v in d.items(): + if v: nd[k] = v + return nd + +def input_urls(urls: list): + ret = [] + + for url in urls: + if os.path.exists(url): + if os.path.splitext(url)[1] == '.txt': + with open(url, 'r+') as fp: + ut = fp.read().split('\n') + for u in ut: + if u: ret.append(u.strip()) + else: ret.append(url) + + return ret + +def get_size(urls: list): + async def contentLength(url): + async with aiohttp.ClientSession() as session: + async with session.head(url) as response: + return response.content_length + + loop = asyncio.get_event_loop() + tasks = [contentLength(url) for url in urls] + totalContentLength = loop.run_until_complete(asyncio.gather(*tasks)) + + return sum(totalContentLength) + +def aud_uri(uri): + data = m3u8.load(uri) + return { + "type": "audio", + "uri": data.base_uri + data.segment_map[0].uri, + "pssh": data.keys[0].uri.split(',')[1] + } + +def mv_uri(url): + streams = [] + data = m3u8.load(url) + + accessibleAudios = [audio for audio in data.media if audio.type == "AUDIO"] + accessibleVideos = data.playlists + + for __audio in accessibleAudios: + streams.append( + { + "type": "audio", + "codec": "HE-AAC" if "HE" in __audio.group_id else "AAC", + "bitrate": __audio.group_id.split('-')[-1] + " kb/s", + "language": __audio.language, + "name": __audio.name, + "channels": __audio.channels, + "uri": __audio.uri + } + ) + + for __video in accessibleVideos: + streams.append( + { + "type": "video", + "codec": "AVC" if "avc" in __video.stream_info.codecs else "HEVC", + "bitrate": f'{round((__video.stream_info.average_bandwidth)/1000000, 2)} Mb/s', + "resolution": f'{__video.stream_info.resolution[0]}x{__video.stream_info.resolution[1]}', + "fps": __video.stream_info.frame_rate, + "range": __video.stream_info.video_range, + "uri": __video.uri + } + ) + + return streams + +def mv_psshs(streams: list): + async def parse(url): + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + data = await response.text() + data = data.strip() + + uris = [] + isKey = False + keyUri = "" + + for line in data.split('\n'): + if line.startswith('#EXT-X-KEY'): + if "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" in line: + isKey = True + for split in line.split('"'): + if split.startswith('data:text/plain'): + keyUri = split + + if '#EXT-X-DISCONTINUITY' in line: + isKey = False + else: + if isKey: + if line.startswith('#EXT-X-MAP:URI'): + uris.append(os.path.dirname(url) + '/' + line.replace('#EXT-X-MAP:URI="', '').replace('"', '')) + if not line.startswith('#'): + uris.append(os.path.dirname(url) + '/' + line) + + return [uris, keyUri.split(',')[1]] + + loop = asyncio.get_event_loop() + tasks = [parse(stream["uri"]) for stream in streams] + parses = loop.run_until_complete(asyncio.gather(*tasks)) + + for i, stream in enumerate(streams): + stream["uri"] = parses[i][0] + stream["pssh"] = parses[i][1] + + return list(set([pssh[1] for pssh in parses])) \ No newline at end of file diff --git a/core/process/__init__.py b/core/process/__init__.py new file mode 100644 index 0000000..5973b4e --- /dev/null +++ b/core/process/__init__.py @@ -0,0 +1,3 @@ +from core.process.download import download +from core.process.process import decrypt, muxhls, cc, muxmv +from core.process.tagger import tag \ No newline at end of file diff --git a/core/process/download.py b/core/process/download.py new file mode 100644 index 0000000..ef0bbdc --- /dev/null +++ b/core/process/download.py @@ -0,0 +1,39 @@ +import requests + +from rich.progress import BarColumn +from rich.progress import DownloadColumn +from rich.progress import Progress +from rich.progress import TextColumn +from rich.progress import TimeRemainingColumn +from rich.progress import TransferSpeedColumn + +from core import parse + +def download(url, filename): + if not isinstance(url, list): + url = [url] + + progress = Progress( + TextColumn(" "), + TextColumn("[bold blue]Downloading"), BarColumn(), + "[progress.percentage]{task.percentage:>3.0f}%", + DownloadColumn(), + TransferSpeedColumn(), + "eta", TimeRemainingColumn() + ) + + print() + + with progress: + taskId = progress.add_task(description='', filename=filename, start=False) + progress.update(taskId, total=parse.get_size(url)) + with open(filename, "wb") as fd: + progress.start_task(taskId) + for u in url: + r = requests.get(u, stream=True) + for data in r.iter_content(chunk_size=32768): + if data: + fd.write(data) + progress.update(taskId, advance=len(data)) + + print() \ No newline at end of file diff --git a/core/process/process.py b/core/process/process.py new file mode 100644 index 0000000..bea1b11 --- /dev/null +++ b/core/process/process.py @@ -0,0 +1,86 @@ +import shutil +import subprocess +from utils import logger + +MP4DECRYPT = 'mp4decrypt' +MP4BOX = 'MP4Box' +CCEXTRACTOR = 'ccextractor' + +if not shutil.which(MP4DECRYPT): + logger.error("Unable to find 'mp4decrypt' in PATH!", 1) + +if not shutil.which(MP4BOX): + logger.error("Unable to find 'MP4Box' in PATH!", 1) + +if not shutil.which(CCEXTRACTOR): + logger.error("Unable to find 'ccextractor' in PATH!", 1) + +def decrypt(input, output, key): + cmd_args = [MP4DECRYPT, "--key", f"1:{key}", input, output] + + try: + retCode = subprocess.Popen( + cmd_args, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT + ).wait() + except: + retCode = 1 + + return retCode + +def cc(input, output): + cmd_args = [CCEXTRACTOR, input, '-o', output] + + try: + retCode = subprocess.Popen( + cmd_args, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT + ).wait() + except: + retCode = 1 + + return retCode + +def muxhls(input, output): + cmd_args = [MP4BOX, "-itags", "tool=", "-add", input, "-new", output] + + try: + retCode = subprocess.Popen( + cmd_args, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT + ).wait() + except: + retCode = 1 + + return retCode + +def muxmv(video, audio, output, at, cc=None): + cmd_args = [MP4BOX, + '-itags', 'tool=', + '-add', f'{video}#video:name=:lang=und', + '-add', f'{audio}#audio:name=:lang={at["language"]}:group=1', + '-new', output] + if cc: + cmd_args[7:7] = ['-add', f'{cc}:group=2'] + + try: + retCode = subprocess.Popen( + cmd_args, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT + ).wait() + except: + retCode = 1 + + return retCode \ No newline at end of file diff --git a/core/process/tagger.py b/core/process/tagger.py new file mode 100644 index 0000000..75f793b --- /dev/null +++ b/core/process/tagger.py @@ -0,0 +1,85 @@ +import os +from mutagen.mp4 import MP4, MP4Cover +from utils import logger + +def tag(media, data, cover, output, nocover=False, nolrc=False): + tags = MP4(media) + tags.delete() + + __tags = { + "\xa9alb": data.get("album"), + "\xa9nam": data.get("song"), + "aART": data.get("albumartist"), + "\xa9ART": data.get("songartist"), + "\xa9wrt": data.get("composer"), + "\xa9gen": data.get("genre"), + "rtng": data.get("rating"), + "\xa9day": data.get("releasedate"), + "cprt": data.get("copyright"), + "stik": data.get("type"), + "\xa9lyr": data.get("lyrics"), + "trkn": (data.get("trackno"), data.get("trackcount")), + "disk": (data.get("discno"), data.get("discno")), + "----:com.apple.itunes:Label": data.get("recordlabel"), + "----:com.apple.itunes:ISRC": data.get("isrc"), + "----:com.apple.itunes:UPC": data.get("upc"), + "----:com.apple.itunes:Lyricist": data.get("songwriter"), + } + + if "credits" in data: + for k, v in data["credits"].items(): + __tags[f'----:com.apple.itunes:{k}'] = v + + if data["type"] == 6: + del __tags["trkn"] + del __tags["disk"] + + for key, value in __tags.items(): + if value: + if isinstance(value, list): + value = ['\r\n'.join(value)] + + if key.startswith("----:com.apple.itunes:"): + value = [val.encode() for val in value] + + tags[key] = value + else: + if key.startswith("----:com.apple.itunes:"): + value = value.encode() + + if key in [ + "aART", + "\xa9ART", + "\xa9wrt", + "\xa9lyr", + "----:com.apple.itunes:Lyricist" + ]: + value = value.replace( + ', ', + '\r\n' + ).replace( + ' & ', + '\r\n' + ) + + tags[key] = [value] + + if not nocover: + logger.info("Embedding artwork...") + tags["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG)] + + if data["type"] == 1: + if not nolrc: + if "timeSyncedLyrics" in data: + logger.info("Saving time-synced lyrics...") + + with open(os.path.join(output[0], output[1], f'{data["file"]}.lrc'), 'w+', encoding="utf8") as l: + l.write( + '\n'.join( + data["timeSyncedLyrics"] + ) + ) + else: + logger.warning("Unable to find time-synced lyrics!") + + tags.save() \ No newline at end of file diff --git a/manzana.py b/manzana.py new file mode 100644 index 0000000..f73e8ad --- /dev/null +++ b/manzana.py @@ -0,0 +1,88 @@ +import argparse + +from rich.console import Console +from rich.traceback import install + +from core import run +from utils import config + +install() + +__version__ = '2.0.0' + +LOGO = r""" + + + [bright_white bold]$$$$$$\$$$$\ $$$$$$\ $$$$$$$\ $$$$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$\ + $$ _$$ _$$\ \____$$\ $$ __$$\ \____$$ |\____$$\ $$ __$$\ \____$$\ + $$ / $$ / $$ | $$$$$$$ |$$ | $$ | $$$$ _/ $$$$$$$ |$$ | $$ | $$$$$$$ | + $$ | $$ | $$ |$$ __$$ |$$ | $$ | $$ _/ $$ __$$ |$$ | $$ |$$ __$$ | + $$ | $$ | $$ |\$$$$$$$ |$$ | $$ |$$$$$$$$\\$$$$$$$ |$$ | $$ |\$$$$$$$ | + \__| \__| \__| \_______|\__| \__|\________|\_______|\__| \__| \_______| + + ──── Apple Music Downloader ────[/] + + +""" + +cons = Console() + +def main(): + parser = argparse.ArgumentParser( + description="Manzana: Apple Music Downloader" + ) + parser.add_argument( + '-v', + '--version', + version=f"Manzana: Apple Music Downloader v{__version__}", + action="version" + ) + parser.add_argument( + '-a', + '--anim-cover', + dest='anim', + help="save animated artwork. [default: False]", + action="store_true" + ) + parser.add_argument( + '-s', + '--skip-video', + dest='skip', + help="skip music-videos inside albums. [default: False]", + action="store_true" + ) + parser.add_argument( + '-ln', + '--no-lrc', + dest='noLrc', + help="don't save time-synced lyrics. [default: False]", + action="store_true" + ) + parser.add_argument( + '-tn', + '--no-tags', + dest='noTags', + help="don't add credits info. [default: False]", + action="store_true" + ) + parser.add_argument( + '-cn', + '--no-cover', + dest='noCover', + help="don't save album artwork. [default: False]", + action="store_true" + ) + parser.add_argument( + 'url', + nargs='+', + help="Apple Music URL(s) for artist, album, song or music-video", + type=str + ) + + return parser.parse_args() + +if __name__ == "__main__": + cons.print(LOGO) + args = main() + config.get_config() + run(args) \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..146bad1 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,3 @@ +from utils.widevine import Device +from utils.widevine import Widevine +from utils.widevine import WidevinePsshData \ No newline at end of file diff --git a/utils/cache.py b/utils/cache.py new file mode 100644 index 0000000..27bd59b --- /dev/null +++ b/utils/cache.py @@ -0,0 +1,33 @@ +import os +import sys +import json + +def __get_path(): + if getattr(sys, 'frozen', False): + return os.path.dirname(sys.executable) + else: + return os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) + +CACHEDIR = os.path.join(__get_path(),'cache') +os.makedirs(CACHEDIR, exist_ok=True) +CACHEFILE = os.path.join(CACHEDIR, 'cache.manzana') + +if not os.path.exists(CACHEFILE): + with open(CACHEFILE, 'w+', encoding='utf8') as fp: + json.dump({}, fp) + +def get(__key): + with open(CACHEFILE, 'r+', encoding='utf8') as fp: + return json.load(fp).get(__key) + +def set(__key, __value): + with open(CACHEFILE, 'r+', encoding='utf8') as fp: + cd = json.load(fp) + cd[__key] = __value + + with open(CACHEFILE, 'w+', encoding='utf8') as fp: + json.dump(cd, fp) \ No newline at end of file diff --git a/utils/config.py b/utils/config.py new file mode 100644 index 0000000..0cfc7d9 --- /dev/null +++ b/utils/config.py @@ -0,0 +1,136 @@ +import os +import sys +import json +import base64 + +from rich import box +from rich.table import Table +from rich.console import Console +from rich.columns import Columns + +from utils import logger + +cons = Console() + +def __get_path(): + if getattr(sys, 'frozen', False): + return os.path.dirname(sys.executable) + else: + return os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) + +CONFIGDIR = os.path.join(__get_path(),'config') +os.makedirs(CONFIGDIR, exist_ok=True) + +DEVICEDIR = os.path.join(__get_path(),'device') +os.makedirs(DEVICEDIR, exist_ok=True) + +CONFIGFILE = os.path.join(CONFIGDIR, 'config.manzana') +DEVICELIST = os.listdir(DEVICEDIR) + +def __get_device(): + logger.info("Loading device...") + + if len(DEVICELIST) == 0: + logger.error("Unable to find a device! Please add a device to continue...", 1) + elif len(DEVICELIST) == 1: + return DEVICELIST[0] + else: + ids = [] + + table = Table(box=box.ROUNDED) + table.add_column("ID", justify="center") + table.add_column("Device", justify="left") + + for i, device in enumerate(DEVICELIST): + table.add_row(str(i), device) + ids.append(i) + + print() + columns = Columns([" ", table]) + cons.print(columns) + id = input("\n\t Enter ID: ") + print() + + if id == "": logger.error("Please enter an ID to continue!", 1) + else: + try: id = int(id) + except: logger.error("Input is not valid!", 1) + + if id in ids: + return DEVICELIST[id] + else: logger.error("ID not found in the list!", 1) + +def get(__key): + with open(CONFIGFILE, 'r+') as fp: + return json.loads( + base64.b64decode( + fp.read() + ).decode() + ).get(__key) + +def set(__key, __value): + with open(CONFIGFILE, 'r+') as fp: + con = json.loads( + base64.b64decode( + fp.read() + ).decode() + ) + con[__key] = __value + + with open(CONFIGFILE, 'w+') as fp: + fp.write( + base64.b64encode( + bytes(json.dumps(con), 'utf8') + ).decode() + ) + +def delete(__key): + with open(CONFIGFILE, 'r+') as fp: + con = json.loads( + base64.b64decode( + fp.read() + ).decode() + ) + + if __key in con: + del con[__key] + + with open(CONFIGFILE, 'w+') as fp: + fp.write( + base64.b64encode( + bytes(json.dumps(con), 'utf8') + ).decode() + ) + +def get_config(): + if not os.path.exists(CONFIGFILE): + con = {} + else: + with open(CONFIGFILE, 'r+') as fp: + con = json.loads( + base64.b64decode( + fp.read() + ).decode() + ) + + device = __get_device() + logger.debug(f'Using device: {device}...') + + con['deviceName'] = device + con['devicePath'] = os.path.join(DEVICEDIR, device) + + if not 'mediaUserToken' in con: + logger.info("Enter your mediaUserToken to continue...") + con['mediaUserToken'] = input('\n\tmediaUserToken: ') + print() + + with open(CONFIGFILE, 'w+') as fp: + fp.write( + base64.b64encode( + bytes(json.dumps(con), 'utf8') + ).decode() + ) \ No newline at end of file diff --git a/utils/keys.py b/utils/keys.py new file mode 100644 index 0000000..04d1dec --- /dev/null +++ b/utils/keys.py @@ -0,0 +1,63 @@ +import os +import sys +import sqlite3 + +def __get_path(): + if getattr(sys, 'frozen', False): + return os.path.dirname(sys.executable) + else: + return os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) + +KEYSDIR = os.path.join(__get_path(),'keys') +os.makedirs(KEYSDIR, exist_ok=True) +KEYSFILE = os.path.join(KEYSDIR, 'keys.db') + +con = sqlite3.connect(KEYSFILE) +cur = con.cursor() +cur.execute(''' + CREATE TABLE IF NOT EXISTS DecryptKeys + ( + PSSH VARCHAR(255) NOT NULL PRIMARY KEY, + KID VARCHAR(255), + KEY VARCHAR(255) NOT NULL + );''' +) +con.commit() +con.close() + +def get(__key): + con = sqlite3.connect(KEYSFILE) + cur = con.cursor() + cur.execute(f'SELECT KEY FROM DecryptKeys WHERE PSSH="{__key}"') + ret = cur.fetchall() + con.commit() + con.close() + + if ret: + return ret[0][0] + return None + +def set(__key, __value): + __value = __value[0].split(':') + + con = sqlite3.connect(KEYSFILE) + cur = con.cursor() + cur.execute(f'''INSERT INTO DecryptKeys + ( + PSSH, + KID, + KEY + ) + VALUES + ( + "{__key}", + "{__value[0]}", + "{__value[1]}" + );''' + ) + con.commit() + con.close() \ No newline at end of file diff --git a/utils/logger.py b/utils/logger.py new file mode 100644 index 0000000..0a3f837 --- /dev/null +++ b/utils/logger.py @@ -0,0 +1,84 @@ +import os +import sys +import logging + +from datetime import datetime, date + +def __get_path(): + if getattr(sys, 'frozen', False): + return os.path.dirname(sys.executable) + else: + return os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) + +LOGSDIR = os.path.join(__get_path(),'logs') +os.makedirs(LOGSDIR, exist_ok=True) + +LOGFILE = os.path.join( + LOGSDIR, + f'manzana_am_log_{date.today().strftime("%y%m%d")}{datetime.now().strftime("%H%M%S")}.log' +) + +fmts = { + logging.DEBUG: '\033[32;1m[{asctime}]\033[0m \033[33;1m[Manzana]\033[0m \033[32;1mDEBUG:\033[0m \033[1;37m{message}\033[0m', + logging.INFO: '\033[32;1m[{asctime}]\033[0m \033[33;1m[Manzana]\033[0m \033[38;5;39;1mINFO:\033[0m \033[1;37m{message}\033[0m', + logging.WARNING: '\033[32;1m[{asctime}]\033[0m \033[33;1m[Manzana]\033[0m \033[31;1mWARN:\033[0m \033[1;37m{message}\033[0m', + logging.ERROR: '\033[32;1m[{asctime}]\033[0m \033[33;1m[Manzana]\033[0m \033[31;1mERROR:\033[0m \033[1;37m{message}\033[0m', + logging.CRITICAL: '\033[32;1m[{asctime}]\033[0m \033[33;1m[Manzana]\033[0m \033[31;1mCRITICAL:\033[0m \033[1;37m{message}\033[0m' +} + +class ManzanaFormatter(logging.Formatter): + def format(self, record): + logfmt = fmts[record.levelno] + formatter = logging.Formatter( + logfmt, + datefmt='%d-%m-%y %H:%M:%S', + style='{' + ) + return formatter.format(record) + +def __get_logger(): + streamHandler = logging.StreamHandler() + streamHandler.setFormatter(ManzanaFormatter()) + streamHandler.setLevel(logging.INFO) + + fileHandler = logging.FileHandler( + filename=LOGFILE, + mode='w', + encoding='utf8' + ) + fileHandler.setFormatter( + logging.Formatter( + fmt='[{asctime}] [Manzana] {levelname}: {message}', + datefmt='%d-%m-%y %H:%M:%S', + style='{' + ) + ) + fileHandler.setLevel(logging.DEBUG) + + logging.basicConfig( + level=logging.DEBUG, + handlers=[streamHandler, fileHandler] + ) + + return logging.getLogger() + +logger = __get_logger() + +def info(msg, exit=0): + logger.info(msg) + if exit: sys.exit(1) + +def error(msg, exit=0): + logger.error(msg) + if exit: sys.exit(1) + +def warning(msg, exit=0): + logger.warning(msg) + if exit: sys.exit(1) + +def debug(msg): + logger.debug(msg) \ No newline at end of file diff --git a/utils/stats.py b/utils/stats.py new file mode 100644 index 0000000..3427012 --- /dev/null +++ b/utils/stats.py @@ -0,0 +1,37 @@ +import os +import sys +import json + +def __get_path(): + if getattr(sys, 'frozen', False): + return os.path.dirname(sys.executable) + else: + return os.path.dirname( + os.path.dirname( + os.path.abspath(__file__) + ) + ) + +TEMPDIR = os.path.join(__get_path(),'temp') +os.makedirs(TEMPDIR, exist_ok=True) + +OUTPUTDIR = os.path.join(__get_path(),'output') +os.makedirs(OUTPUTDIR, exist_ok=True) + +STATSFILE = os.path.join(TEMPDIR, 'progress.mstats') + +if not os.path.exists(STATSFILE): + with open(STATSFILE, 'w+', encoding='utf8') as fp: + json.dump({}, fp) + +def get(__key): + with open(STATSFILE, 'r+', encoding='utf8') as fp: + return json.load(fp).get(__key) + +def set(__key, __value): + with open(STATSFILE, 'r+', encoding='utf8') as fp: + cd = json.load(fp) + cd[__key] = __value + + with open(STATSFILE, 'w+', encoding='utf8') as fp: + json.dump(cd, fp) \ No newline at end of file diff --git a/utils/widevine/__init__.py b/utils/widevine/__init__.py new file mode 100644 index 0000000..3a88f3f --- /dev/null +++ b/utils/widevine/__init__.py @@ -0,0 +1,3 @@ +from utils.widevine.formats.widevine_pssh_data_pb2 import WidevinePsshData +from utils.widevine.widevine import Widevine +from utils.widevine.cdm import Device \ No newline at end of file diff --git a/utils/widevine/cdm.py b/utils/widevine/cdm.py new file mode 100644 index 0000000..790e860 --- /dev/null +++ b/utils/widevine/cdm.py @@ -0,0 +1,319 @@ +import os +import time +import base64 +import binascii + +from google.protobuf.message import DecodeError +from Cryptodome.Random import get_random_bytes +from Cryptodome.Random import random +from Cryptodome.Cipher import PKCS1_OAEP, AES +from Cryptodome.Hash import CMAC, SHA256, HMAC, SHA1 +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import pss +from Cryptodome.Util import Padding + +from utils import logger +import utils.widevine.formats.wv_proto2_pb2 as wv_proto2 + +class Session: + def __init__(self, sessionId, initData, deviceConfig, offline): + self.sessionId = sessionId + self.initData = initData + self.offline = offline + self.deviceConfig = deviceConfig + self.deviceKey = None + self.sessionKey = None + self.derivedKeys = { + 'enc': None, + 'auth_1': None, + 'auth_2': None + } + self.licenseRequest = None + self.license = None + self.serviceCertificate = None + self.privacyMode = False + self.keys = [] + +class Key: + def __init__(self, kid, type, key, permissions=[]): + self.kid = kid + self.type = type + self.key = key + self.permissions = permissions + + def __repr__(self): + if self.type == "OPERATOR_SESSION": + return "key(kid={}, type={}, key={}, permissions={})".format( + self.kid, + self.type, + binascii.hexlify(self.key), + self.permissions + ) + else: + return "key(kid={}, type={}, key={})".format( + self.kid, + self.type, + binascii.hexlify(self.key) + ) + +class Device: + def __init__(self, deviceName, devicePath): + self.deviceName = deviceName + self.securityLevel = 3 + self.deviceType = 'android' + self.isPrivateKey = os.path.exists( + os.path.join(devicePath, 'device_private_key') + ) + self.isSendKeyControlNonce = True + self.isVmp = os.path.exists( + os.path.join(devicePath, 'device_vmp_blob') + ) + self.description = 'Widevine' + self.keyboxFilename = os.path.join( + devicePath, 'keybox') + self.deviceCertFilename = os.path.join( + devicePath, 'device_cert') + self.devicePrivateKeyFilename = os.path.join( + devicePath, 'device_private_key') + self.deviceClientIdBlobFilename = os.path.join( + devicePath, 'device_client_id_blob') + self.deviceVmpBlobFilename = os.path.join( + devicePath, 'device_vmp_blob') + +class ContentDecryptionModule: + def __init__(self): + self.sessions = {} + + def open(self, initData, device: Device, rawData=None, offline=False): + if device.deviceType == 'android': + randAscii = ''.join(random.choice('ABCDEF0123456789') for _ in range(16)) + counter = '01' + rest = '00000000000000' + sessionId = randAscii + counter + rest + sessionId = sessionId.encode('ascii') + + elif device.deviceType == 'chrome': + randBytes = get_random_bytes(16) + sessionId = randBytes + + else: logger.error("Device type is unusable!", 1) + + if rawData and isinstance(rawData, (bytes, bytearray)): + initData = rawData + self.rawPssh = True + else: + initData = self.__parseInitData(initData) + self.rawPssh = False + + if initData: newSession = Session(sessionId, initData, device, offline) + else: logger.error("Unable to parse init data!") + + self.sessions[sessionId] = newSession + return sessionId + + def __parseInitData(self, initData): + initDataParsed = wv_proto2.WidevineCencHeader() + + try: + initDataParsed.ParseFromString(base64.b64decode(initData)[32:]) + except DecodeError: + try: + id_bytes = initDataParsed.ParseFromString(base64.b64decode(initData)[32:]) + except DecodeError: + return None + + return initDataParsed + + def close(self, sessionId): + if sessionId in self.sessions: self.sessions.pop(sessionId) + else: logger.error(f"Session {sessionId} not found!") + + def setServiceCertificate(self, sessionId, cert): + if not sessionId in self.sessions: + logger.error("session id doesn't exist!") + + session: Session = self.sessions[sessionId] + message = wv_proto2.SignedMessage() + + try: message.ParseFromString(base64.b64decode(cert)) + except DecodeError: logger.error("Failed to parse cert as SignedMessage!") + + serviceCertificate = wv_proto2.SignedDeviceCertificate() + + if message.Type: + try: serviceCertificate.ParseFromString(message.Msg) + except DecodeError: logger.error("Failed to parse Service Certificate!") + else: + try: serviceCertificate.ParseFromString(base64.b64decode(cert)) + except DecodeError: logger.error("Failed to parse Service Certificate!") + + session.serviceCertificate = serviceCertificate + session.privacyMode = True + + def getLicenseRequest(self, sessionId): + if not sessionId in self.sessions: + logger.error("Session ID does not exist!") + + session: Session = self.sessions[sessionId] + + if self.rawPssh: licenseRequest = wv_proto2.SignedLicenseRequestRaw() + else: licenseRequest = wv_proto2.SignedLicenseRequest() + + clientId = wv_proto2.ClientIdentification() + + if not os.path.exists(session.deviceConfig.deviceClientIdBlobFilename): + logger.error("No Client ID Blob available for this device!", 1) + + with open(session.deviceConfig.deviceClientIdBlobFilename, "rb") as f: + try: cidBytes = clientId.ParseFromString(f.read()) + except DecodeError: logger.error("Client ID failed to parse as protobuf!", 1) + + if not self.rawPssh: + licenseRequest.Type = wv_proto2.SignedLicenseRequest.MessageType.Value('LICENSE_REQUEST') + licenseRequest.Msg.ContentId.CencId.Pssh.CopyFrom(session.initData) + else: + licenseRequest.Type = wv_proto2.SignedLicenseRequestRaw.MessageType.Value('LICENSE_REQUEST') + licenseRequest.Msg.ContentId.CencId.Pssh = session.initData # bytes + + if session.offline: licenseType = wv_proto2.LicenseType.Value('OFFLINE') + else: licenseType = wv_proto2.LicenseType.Value('DEFAULT') + + licenseRequest.Msg.ContentId.CencId.LicenseType = licenseType + licenseRequest.Msg.ContentId.CencId.RequestId = sessionId + licenseRequest.Msg.Type = wv_proto2.LicenseRequest.RequestType.Value('NEW') + licenseRequest.Msg.RequestTime = int(time.time()) + licenseRequest.Msg.ProtocolVersion = wv_proto2.ProtocolVersion.Value('CURRENT') + + if session.deviceConfig.isSendKeyControlNonce: + licenseRequest.Msg.KeyControlNonce = random.randrange(1, 2**31) + + if session.privacyMode: + if session.deviceConfig.isVmp: + vmpHashes = wv_proto2.FileHashes() + + with open(session.deviceConfig.deviceVmpBlobFilename, "rb") as f: + try: vmpBytes = vmpHashes.ParseFromString(f.read()) + except DecodeError: logger.error("VMP hashes failed to parse as protobuf!", 1) + + clientId._FileHashes.CopyFrom(vmpHashes) + + cidAesKey = get_random_bytes(16) + cidIv = get_random_bytes(16) + cidCipher = AES.new(cidAesKey, AES.MODE_CBC, cidIv) + encryptedClientId = cidCipher.encrypt(Padding.pad(clientId.SerializeToString(), 16)) + servicePublicKey = RSA.importKey(session.serviceCertificate._DeviceCertificate.PublicKey) + serviceCipher = PKCS1_OAEP.new(servicePublicKey) + encryptedCidKey = serviceCipher.encrypt(cidAesKey) + encryptedClientIdProto = wv_proto2.EncryptedClientIdentification() + encryptedClientIdProto.ServiceId = session.serviceCertificate._DeviceCertificate.ServiceId + encryptedClientIdProto.ServiceCertificateSerialNumber = session.serviceCertificate._DeviceCertificate.SerialNumber + encryptedClientIdProto.EncryptedClientId = encryptedClientId + encryptedClientIdProto.EncryptedClientIdIv = cidIv + encryptedClientIdProto.EncryptedPrivacyKey = encryptedCidKey + licenseRequest.Msg.EncryptedClientId.CopyFrom(encryptedClientIdProto) + else: + licenseRequest.Msg.ClientId.CopyFrom(clientId) + + if session.deviceConfig.isPrivateKey: + key = RSA.importKey(open(session.deviceConfig.devicePrivateKeyFilename).read()) + session.deviceKey = key + else: + logger.error("Need device private key, other methods unimplemented", 1) + + hash = SHA1.new(licenseRequest.Msg.SerializeToString()) + signature = pss.new(key).sign(hash) + + licenseRequest.Signature = signature + session.licenseRequest = licenseRequest + return licenseRequest.SerializeToString() + + def provideLicense(self, sessionId, b64License): + + if not sessionId in self.sessions: + logger.error("Session does not exist!") + + session: Session = self.sessions[sessionId] + + if not session.licenseRequest: + logger.error("Generate a License Request first!", 1) + + license = wv_proto2.SignedLicense() + try: license.ParseFromString(base64.b64decode(b64License)) + except DecodeError: logger.error("Unable to parse license - check Protobufs!", 1) + + session.license = license + + oaepCipher = PKCS1_OAEP.new(session.deviceKey) + session.sessionKey = oaepCipher.decrypt(license.SessionKey) + licReqMsg = session.licenseRequest.Msg.SerializeToString() + encKeyBase = b"ENCRYPTION\000" + licReqMsg + b"\0\0\0\x80" + authKeyBase = b"AUTHENTICATION\0" + licReqMsg + b"\0\0\2\0" + + encKey = b"\x01" + encKeyBase + authKey_1 = b"\x01" + authKeyBase + authKey_2 = b"\x02" + authKeyBase + authKey_3 = b"\x03" + authKeyBase + authKey_4 = b"\x04" + authKeyBase + + cmacObj = CMAC.new(session.sessionKey, ciphermod=AES) + cmacObj.update(encKey) + encCmacKey = cmacObj.digest() + + cmacObj = CMAC.new(session.sessionKey, ciphermod=AES) + cmacObj.update(authKey_1) + authCmacKey_1 = cmacObj.digest() + + cmacObj = CMAC.new(session.sessionKey, ciphermod=AES) + cmacObj.update(authKey_2) + authCmacKey_2 = cmacObj.digest() + + cmacObj = CMAC.new(session.sessionKey, ciphermod=AES) + cmacObj.update(authKey_3) + authCmacKey_3 = cmacObj.digest() + + cmacObj = CMAC.new(session.sessionKey, ciphermod=AES) + cmacObj.update(authKey_4) + authCmacKey_4 = cmacObj.digest() + + authCmacCombined_1 = authCmacKey_1 + authCmacKey_2 + authCmacCombined_2 = authCmacKey_3 + authCmacKey_4 + + session.derivedKeys['enc'] = encCmacKey + session.derivedKeys['auth_1'] = authCmacCombined_1 + session.derivedKeys['auth_2'] = authCmacCombined_2 + + licHmac = HMAC.new(session.derivedKeys['auth_1'], digestmod=SHA256) + licHmac.update(license.Msg.SerializeToString()) + + if licHmac.digest() != license.Signature: + with open("originalLic.bin", "wb") as f: + f.write(base64.b64decode(b64License)) + with open("parsedLic.bin", "wb") as f: + f.write(license.SerializeToString()) + + for key in license.Msg.Key: + if key.Id: keyId = key.Id + else: keyId = wv_proto2.License.KeyContainer.KeyType.Name(key.Type).encode('utf-8') + + encryptedKey = key.Key + iv = key.Iv + type = wv_proto2.License.KeyContainer.KeyType.Name(key.Type) + + cipher = AES.new(session.derivedKeys['enc'], AES.MODE_CBC, iv=iv) + decryptedKey = cipher.decrypt(encryptedKey) + + if type == "OPERATOR_SESSION": + permissions = [] + perms = key._OperatorSessionKeyPermissions + + for (descriptor, value) in perms.ListFields(): + if value == 1: + permissions.append(descriptor.name) + else: + permissions = [] + + session.keys.append(Key(keyId, type, Padding.unpad(decryptedKey, 16), permissions)) + + def getKeys(self, sessionId): + if sessionId in self.sessions: return self.sessions[sessionId].keys + else: logger.error("Session ID not found!", 1) diff --git a/utils/widevine/formats/widevine_pssh_data.proto b/utils/widevine/formats/widevine_pssh_data.proto new file mode 100644 index 0000000..8c67f00 --- /dev/null +++ b/utils/widevine/formats/widevine_pssh_data.proto @@ -0,0 +1,56 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// This file defines Widevine Pssh Data proto format. + +syntax = "proto2"; + +package shaka.media; + +message WidevinePsshData { + enum Algorithm { + UNENCRYPTED = 0; + AESCTR = 1; + }; + optional Algorithm algorithm = 1; + repeated bytes key_id = 2; + + // Content provider name. + optional string provider = 3; + + // A content identifier, specified by content provider. + optional bytes content_id = 4; + + // The name of a registered policy to be used for this asset. + optional string policy = 6; + + // Crypto period index, for media using key rotation. + optional uint32 crypto_period_index = 7; + + // Optional protected context for group content. The grouped_license is a + // serialized SignedMessage. + optional bytes grouped_license = 8; + + // Protection scheme identifying the encryption algorithm. Represented as one + // of the following 4CC values: 'cenc' (AES-CTR), 'cbc1' (AES-CBC), + // 'cens' (AES-CTR subsample), 'cbcs' (AES-CBC subsample). + optional uint32 protection_scheme = 9; +} + +// Derived from WidevinePsshData. The JSON format of this proto is used in +// Widevine HLS DRM signaling v1. +// We cannot build JSON from WidevinePsshData as |key_id| is required to be in +// hex format, while |bytes| type is translated to base64 by JSON formatter, so +// we have to use |string| type and do hex conversion in the code. +message WidevineHeader { + repeated string key_ids = 2; + + // Content provider name. + optional string provider = 3; + + // A content identifier, specified by content provider. + optional bytes content_id = 4; +} diff --git a/utils/widevine/formats/widevine_pssh_data_pb2.py b/utils/widevine/formats/widevine_pssh_data_pb2.py new file mode 100644 index 0000000..1f40dfc --- /dev/null +++ b/utils/widevine/formats/widevine_pssh_data_pb2.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: widevine_pssh_data.proto + +"""Generated protocol buffer code.""" + +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18widevine_pssh_data.proto\x12\x0bshaka.media\"\x8f\x02\n\x10WidevinePsshData\x12:\n\talgorithm\x18\x01 \x01(\x0e\x32\'.shaka.media.WidevinePsshData.Algorithm\x12\x0e\n\x06key_id\x18\x02 \x03(\x0c\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x0e\n\x06policy\x18\x06 \x01(\t\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x17\n\x0fgrouped_license\x18\x08 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\t \x01(\r\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"G\n\x0eWidevineHeader\x12\x0f\n\x07key_ids\x18\x02 \x03(\t\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c') + +_WIDEVINEPSSHDATA = DESCRIPTOR.message_types_by_name['WidevinePsshData'] +_WIDEVINEHEADER = DESCRIPTOR.message_types_by_name['WidevineHeader'] +_WIDEVINEPSSHDATA_ALGORITHM = _WIDEVINEPSSHDATA.enum_types_by_name['Algorithm'] + +WidevinePsshData = _reflection.GeneratedProtocolMessageType('WidevinePsshData', (_message.Message,), { + 'DESCRIPTOR' : _WIDEVINEPSSHDATA, + '__module__' : 'widevine_pssh_data_pb2' + # @@protoc_insertion_point(class_scope:shaka.media.WidevinePsshData) + }) +_sym_db.RegisterMessage(WidevinePsshData) + +WidevineHeader = _reflection.GeneratedProtocolMessageType('WidevineHeader', (_message.Message,), { + 'DESCRIPTOR' : _WIDEVINEHEADER, + '__module__' : 'widevine_pssh_data_pb2' + # @@protoc_insertion_point(class_scope:shaka.media.WidevineHeader) + }) +_sym_db.RegisterMessage(WidevineHeader) + +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _WIDEVINEPSSHDATA._serialized_start=42 + _WIDEVINEPSSHDATA._serialized_end=313 + _WIDEVINEPSSHDATA_ALGORITHM._serialized_start=273 + _WIDEVINEPSSHDATA_ALGORITHM._serialized_end=313 + _WIDEVINEHEADER._serialized_start=315 + _WIDEVINEHEADER._serialized_end=386 +# @@protoc_insertion_point(module_scope) diff --git a/utils/widevine/formats/wv_proto2.proto b/utils/widevine/formats/wv_proto2.proto new file mode 100644 index 0000000..c06b18d --- /dev/null +++ b/utils/widevine/formats/wv_proto2.proto @@ -0,0 +1,466 @@ +syntax = "proto2"; + +// from x86 (partial), most of it from the ARM version: +message ClientIdentification { + enum TokenType { + KEYBOX = 0; + DEVICE_CERTIFICATE = 1; + REMOTE_ATTESTATION_CERTIFICATE = 2; + } + message NameValue { + required string Name = 1; + required string Value = 2; + } + message ClientCapabilities { + enum HdcpVersion { + HDCP_NONE = 0; + HDCP_V1 = 1; + HDCP_V2 = 2; + HDCP_V2_1 = 3; + HDCP_V2_2 = 4; + } + optional uint32 ClientToken = 1; + optional uint32 SessionToken = 2; + optional uint32 VideoResolutionConstraints = 3; + optional HdcpVersion MaxHdcpVersion = 4; + optional uint32 OemCryptoApiVersion = 5; + } + required TokenType Type = 1; + //optional bytes Token = 2; // by default the client treats this as blob, but it's usually a DeviceCertificate, so for usefulness sake, I'm replacing it with this one: + optional SignedDeviceCertificate Token = 2; // use this when parsing, "bytes" when building a client id blob + repeated NameValue ClientInfo = 3; + optional bytes ProviderClientToken = 4; + optional uint32 LicenseCounter = 5; + optional ClientCapabilities _ClientCapabilities = 6; // how should we deal with duped names? will have to look at proto docs later + optional FileHashes _FileHashes = 7; // vmp blob goes here +} + +message DeviceCertificate { + enum CertificateType { + ROOT = 0; + INTERMEDIATE = 1; + USER_DEVICE = 2; + SERVICE = 3; + } + required CertificateType Type = 1; // the compiled code reused this as ProvisionedDeviceInfo.WvSecurityLevel, however that is incorrect (compiler aliased it as they're both identical as a structure) + optional bytes SerialNumber = 2; + optional uint32 CreationTimeSeconds = 3; + optional bytes PublicKey = 4; + optional uint32 SystemId = 5; + optional uint32 TestDeviceDeprecated = 6; // is it bool or int? + optional bytes ServiceId = 7; // service URL for service certificates +} + +// missing some references, +message DeviceCertificateStatus { + enum CertificateStatus { + VALID = 0; + REVOKED = 1; + } + optional bytes SerialNumber = 1; + optional CertificateStatus Status = 2; + optional ProvisionedDeviceInfo DeviceInfo = 4; // where is 3? is it deprecated? +} + +message DeviceCertificateStatusList { + optional uint32 CreationTimeSeconds = 1; + repeated DeviceCertificateStatus CertificateStatus = 2; +} + +message EncryptedClientIdentification { + required string ServiceId = 1; + optional bytes ServiceCertificateSerialNumber = 2; + required bytes EncryptedClientId = 3; + required bytes EncryptedClientIdIv = 4; + required bytes EncryptedPrivacyKey = 5; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +enum LicenseType { + ZERO = 0; + DEFAULT = 1; // 1 is STREAMING/temporary license; on recent versions may go up to 3 (latest x86); it might be persist/don't persist type, unconfirmed + OFFLINE = 2; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +// this is just a guess because these globals got lost, but really, do we need more? +enum ProtocolVersion { + CURRENT = 21; // don't have symbols for this +} + + +message LicenseIdentification { + optional bytes RequestId = 1; + optional bytes SessionId = 2; + optional bytes PurchaseId = 3; + optional LicenseType Type = 4; + optional uint32 Version = 5; + optional bytes ProviderSessionToken = 6; +} + + +message License { + message Policy { + optional bool CanPlay = 1; // changed from uint32 to bool + optional bool CanPersist = 2; + optional bool CanRenew = 3; + optional uint32 RentalDurationSeconds = 4; + optional uint32 PlaybackDurationSeconds = 5; + optional uint32 LicenseDurationSeconds = 6; + optional uint32 RenewalRecoveryDurationSeconds = 7; + optional string RenewalServerUrl = 8; + optional uint32 RenewalDelaySeconds = 9; + optional uint32 RenewalRetryIntervalSeconds = 10; + optional bool RenewWithUsage = 11; // was uint32 + } + message KeyContainer { + enum KeyType { + SIGNING = 1; + CONTENT = 2; + KEY_CONTROL = 3; + OPERATOR_SESSION = 4; + } + enum SecurityLevel { + SW_SECURE_CRYPTO = 1; + SW_SECURE_DECODE = 2; + HW_SECURE_CRYPTO = 3; + HW_SECURE_DECODE = 4; + HW_SECURE_ALL = 5; + } + message OutputProtection { + enum CGMS { + COPY_FREE = 0; + COPY_ONCE = 2; + COPY_NEVER = 3; + CGMS_NONE = 0x2A; // PC default! + } + optional ClientIdentification.ClientCapabilities.HdcpVersion Hdcp = 1; // it's most likely a copy of Hdcp version available here, but compiler optimized it away + optional CGMS CgmsFlags = 2; + } + message KeyControl { + required bytes KeyControlBlock = 1; // what is this? + required bytes Iv = 2; + } + message OperatorSessionKeyPermissions { + optional uint32 AllowEncrypt = 1; + optional uint32 AllowDecrypt = 2; + optional uint32 AllowSign = 3; + optional uint32 AllowSignatureVerify = 4; + } + message VideoResolutionConstraint { + optional uint32 MinResolutionPixels = 1; + optional uint32 MaxResolutionPixels = 2; + optional OutputProtection RequiredProtection = 3; + } + optional bytes Id = 1; + optional bytes Iv = 2; + optional bytes Key = 3; + optional KeyType Type = 4; + optional SecurityLevel Level = 5; + optional OutputProtection RequiredProtection = 6; + optional OutputProtection RequestedProtection = 7; + optional KeyControl _KeyControl = 8; // duped names, etc + optional OperatorSessionKeyPermissions _OperatorSessionKeyPermissions = 9; // duped names, etc + repeated VideoResolutionConstraint VideoResolutionConstraints = 10; + } + optional LicenseIdentification Id = 1; + optional Policy _Policy = 2; // duped names, etc + repeated KeyContainer Key = 3; + optional uint32 LicenseStartTime = 4; + optional uint32 RemoteAttestationVerified = 5; // bool? + optional bytes ProviderClientToken = 6; + // there might be more, check with newer versions (I see field 7-8 in a lic) + // this appeared in latest x86: + optional uint32 ProtectionScheme = 7; // type unconfirmed fully, but it's likely as WidevineCencHeader describesit (fourcc) +} + +message LicenseError { + enum Error { + INVALID_DEVICE_CERTIFICATE = 1; + REVOKED_DEVICE_CERTIFICATE = 2; + SERVICE_UNAVAILABLE = 3; + } + //LicenseRequest.RequestType ErrorCode; // clang mismatch + optional Error ErrorCode = 1; +} + +message LicenseRequest { + message ContentIdentification { + message CENC { + //optional bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + optional WidevineCencHeader Pssh = 1; + optional LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 (is this persist/don't persist? look into it!) + optional bytes RequestId = 3; + } + message WebM { + optional bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + optional LicenseType LicenseType = 2; + optional bytes RequestId = 3; + } + message ExistingLicense { + optional LicenseIdentification LicenseId = 1; + optional uint32 SecondsSinceStarted = 2; + optional uint32 SecondsSinceLastPlayed = 3; + optional bytes SessionUsageTableEntry = 4; // interesting! try to figure out the connection between the usage table blob and KCB! + } + optional CENC CencId = 1; + optional WebM WebmId = 2; + optional ExistingLicense License = 3; + } + enum RequestType { + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + optional ClientIdentification ClientId = 1; + optional ContentIdentification ContentId = 2; + optional RequestType Type = 3; + optional uint32 RequestTime = 4; + optional bytes KeyControlNonceDeprecated = 5; + optional ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + optional uint32 KeyControlNonce = 7; + optional EncryptedClientIdentification EncryptedClientId = 8; +} + +// raw pssh hack +message LicenseRequestRaw { + message ContentIdentification { + message CENC { + optional bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + //optional WidevineCencHeader Pssh = 1; + optional LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 (is this persist/don't persist? look into it!) + optional bytes RequestId = 3; + } + message WebM { + optional bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + optional LicenseType LicenseType = 2; + optional bytes RequestId = 3; + } + message ExistingLicense { + optional LicenseIdentification LicenseId = 1; + optional uint32 SecondsSinceStarted = 2; + optional uint32 SecondsSinceLastPlayed = 3; + optional bytes SessionUsageTableEntry = 4; // interesting! try to figure out the connection between the usage table blob and KCB! + } + optional CENC CencId = 1; + optional WebM WebmId = 2; + optional ExistingLicense License = 3; + } + enum RequestType { + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + optional ClientIdentification ClientId = 1; + optional ContentIdentification ContentId = 2; + optional RequestType Type = 3; + optional uint32 RequestTime = 4; + optional bytes KeyControlNonceDeprecated = 5; + optional ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + optional uint32 KeyControlNonce = 7; + optional EncryptedClientIdentification EncryptedClientId = 8; +} + + +message ProvisionedDeviceInfo { + enum WvSecurityLevel { + LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; + } + optional uint32 SystemId = 1; + optional string Soc = 2; + optional string Manufacturer = 3; + optional string Model = 4; + optional string DeviceType = 5; + optional uint32 ModelYear = 6; + optional WvSecurityLevel SecurityLevel = 7; + optional uint32 TestDevice = 8; // bool? +} + + +// todo: fill +message ProvisioningOptions { +} + +// todo: fill +message ProvisioningRequest { +} + +// todo: fill +message ProvisioningResponse { +} + +message RemoteAttestation { + optional EncryptedClientIdentification Certificate = 1; + optional string Salt = 2; + optional string Signature = 3; +} + +// todo: fill +message SessionInit { +} + +// todo: fill +message SessionState { +} + +// todo: fill +message SignedCertificateStatusList { +} + +message SignedDeviceCertificate { + + //optional bytes DeviceCertificate = 1; // again, they use a buffer where it's supposed to be a message, so we'll replace it with what it really is: + optional DeviceCertificate _DeviceCertificate = 1; // how should we deal with duped names? will have to look at proto docs later + optional bytes Signature = 2; + optional SignedDeviceCertificate Signer = 3; +} + + +// todo: fill +message SignedProvisioningMessage { +} + +// the root of all messages, from either server or client +message SignedMessage { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional bytes Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + + + +// This message is copied from google's docs, not reversed: +message WidevineCencHeader { + enum Algorithm { + UNENCRYPTED = 0; + AESCTR = 1; + }; + optional Algorithm algorithm = 1; + repeated bytes key_id = 2; + + // Content provider name. + optional string provider = 3; + + // A content identifier, specified by content provider. + optional bytes content_id = 4; + + // Track type. Acceptable values are SD, HD and AUDIO. Used to + // differentiate content keys used by an asset. + optional string track_type_deprecated = 5; + + // The name of a registered policy to be used for this asset. + optional string policy = 6; + + // Crypto period index, for media using key rotation. + optional uint32 crypto_period_index = 7; + + // Optional protected context for group content. The grouped_license is a + // serialized SignedMessage. + optional bytes grouped_license = 8; + + // Protection scheme identifying the encryption algorithm. + // Represented as one of the following 4CC values: + // 'cenc' (AESCTR), 'cbc1' (AESCBC), + // 'cens' (AESCTR subsample), 'cbcs' (AESCBC subsample). + optional uint32 protection_scheme = 9; + + // Optional. For media using key rotation, this represents the duration + // of each crypto period in seconds. + optional uint32 crypto_period_seconds = 10; +} + + +// remove these when using it outside of protoc: + +// from here on, it's just for testing, these messages don't exist in the binaries, I'm adding them to avoid detecting type programmatically +message SignedLicenseRequest { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional LicenseRequest Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +// hack +message SignedLicenseRequestRaw { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional LicenseRequestRaw Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + + +message SignedLicense { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional License Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +message SignedServiceCertificate { + enum MessageType { + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + optional MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + optional SignedDeviceCertificate Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + optional bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + optional bytes SessionKey = 4; // often RSA wrapped for licenses + optional RemoteAttestation RemoteAttestation = 5; +} + +//vmp support +message FileHashes { + message Signature { + optional string filename = 1; + optional bool test_signing = 2; //0 - release, 1 - testing + optional bytes SHA512Hash = 3; + optional bool main_exe = 4; //0 for dlls, 1 for exe, this is field 3 in file + optional bytes signature = 5; + } + optional bytes signer = 1; + repeated Signature signatures = 2; +} diff --git a/utils/widevine/formats/wv_proto2_pb2.py b/utils/widevine/formats/wv_proto2_pb2.py new file mode 100644 index 0000000..88eb294 --- /dev/null +++ b/utils/widevine/formats/wv_proto2_pb2.py @@ -0,0 +1,147 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: wv_proto2.proto + +"""Generated protocol buffer code.""" + +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fwv_proto2.proto\"\xe7\x05\n\x14\x43lientIdentification\x12-\n\x04Type\x18\x01 \x02(\x0e\x32\x1f.ClientIdentification.TokenType\x12\'\n\x05Token\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x33\n\nClientInfo\x18\x03 \x03(\x0b\x32\x1f.ClientIdentification.NameValue\x12\x1b\n\x13ProviderClientToken\x18\x04 \x01(\x0c\x12\x16\n\x0eLicenseCounter\x18\x05 \x01(\r\x12\x45\n\x13_ClientCapabilities\x18\x06 \x01(\x0b\x32(.ClientIdentification.ClientCapabilities\x12 \n\x0b_FileHashes\x18\x07 \x01(\x0b\x32\x0b.FileHashes\x1a(\n\tNameValue\x12\x0c\n\x04Name\x18\x01 \x02(\t\x12\r\n\x05Value\x18\x02 \x02(\t\x1a\xa4\x02\n\x12\x43lientCapabilities\x12\x13\n\x0b\x43lientToken\x18\x01 \x01(\r\x12\x14\n\x0cSessionToken\x18\x02 \x01(\r\x12\"\n\x1aVideoResolutionConstraints\x18\x03 \x01(\r\x12L\n\x0eMaxHdcpVersion\x18\x04 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12\x1b\n\x13OemCryptoApiVersion\x18\x05 \x01(\r\"T\n\x0bHdcpVersion\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\"S\n\tTokenType\x12\n\n\x06KEYBOX\x10\x00\x12\x16\n\x12\x44\x45VICE_CERTIFICATE\x10\x01\x12\"\n\x1eREMOTE_ATTESTATION_CERTIFICATE\x10\x02\"\x9b\x02\n\x11\x44\x65viceCertificate\x12\x30\n\x04Type\x18\x01 \x02(\x0e\x32\".DeviceCertificate.CertificateType\x12\x14\n\x0cSerialNumber\x18\x02 \x01(\x0c\x12\x1b\n\x13\x43reationTimeSeconds\x18\x03 \x01(\r\x12\x11\n\tPublicKey\x18\x04 \x01(\x0c\x12\x10\n\x08SystemId\x18\x05 \x01(\r\x12\x1c\n\x14TestDeviceDeprecated\x18\x06 \x01(\r\x12\x11\n\tServiceId\x18\x07 \x01(\x0c\"K\n\x0f\x43\x65rtificateType\x12\x08\n\x04ROOT\x10\x00\x12\x10\n\x0cINTERMEDIATE\x10\x01\x12\x0f\n\x0bUSER_DEVICE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\"\xc4\x01\n\x17\x44\x65viceCertificateStatus\x12\x14\n\x0cSerialNumber\x18\x01 \x01(\x0c\x12:\n\x06Status\x18\x02 \x01(\x0e\x32*.DeviceCertificateStatus.CertificateStatus\x12*\n\nDeviceInfo\x18\x04 \x01(\x0b\x32\x16.ProvisionedDeviceInfo\"+\n\x11\x43\x65rtificateStatus\x12\t\n\x05VALID\x10\x00\x12\x0b\n\x07REVOKED\x10\x01\"o\n\x1b\x44\x65viceCertificateStatusList\x12\x1b\n\x13\x43reationTimeSeconds\x18\x01 \x01(\r\x12\x33\n\x11\x43\x65rtificateStatus\x18\x02 \x03(\x0b\x32\x18.DeviceCertificateStatus\"\xaf\x01\n\x1d\x45ncryptedClientIdentification\x12\x11\n\tServiceId\x18\x01 \x02(\t\x12&\n\x1eServiceCertificateSerialNumber\x18\x02 \x01(\x0c\x12\x19\n\x11\x45ncryptedClientId\x18\x03 \x02(\x0c\x12\x1b\n\x13\x45ncryptedClientIdIv\x18\x04 \x02(\x0c\x12\x1b\n\x13\x45ncryptedPrivacyKey\x18\x05 \x02(\x0c\"\x9c\x01\n\x15LicenseIdentification\x12\x11\n\tRequestId\x18\x01 \x01(\x0c\x12\x11\n\tSessionId\x18\x02 \x01(\x0c\x12\x12\n\nPurchaseId\x18\x03 \x01(\x0c\x12\x1a\n\x04Type\x18\x04 \x01(\x0e\x32\x0c.LicenseType\x12\x0f\n\x07Version\x18\x05 \x01(\r\x12\x1c\n\x14ProviderSessionToken\x18\x06 \x01(\x0c\"\xa1\x0e\n\x07License\x12\"\n\x02Id\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12 \n\x07_Policy\x18\x02 \x01(\x0b\x32\x0f.License.Policy\x12\"\n\x03Key\x18\x03 \x03(\x0b\x32\x15.License.KeyContainer\x12\x18\n\x10LicenseStartTime\x18\x04 \x01(\r\x12!\n\x19RemoteAttestationVerified\x18\x05 \x01(\r\x12\x1b\n\x13ProviderClientToken\x18\x06 \x01(\x0c\x12\x18\n\x10ProtectionScheme\x18\x07 \x01(\r\x1a\xbb\x02\n\x06Policy\x12\x0f\n\x07\x43\x61nPlay\x18\x01 \x01(\x08\x12\x12\n\nCanPersist\x18\x02 \x01(\x08\x12\x10\n\x08\x43\x61nRenew\x18\x03 \x01(\x08\x12\x1d\n\x15RentalDurationSeconds\x18\x04 \x01(\r\x12\x1f\n\x17PlaybackDurationSeconds\x18\x05 \x01(\r\x12\x1e\n\x16LicenseDurationSeconds\x18\x06 \x01(\r\x12&\n\x1eRenewalRecoveryDurationSeconds\x18\x07 \x01(\r\x12\x18\n\x10RenewalServerUrl\x18\x08 \x01(\t\x12\x1b\n\x13RenewalDelaySeconds\x18\t \x01(\r\x12#\n\x1bRenewalRetryIntervalSeconds\x18\n \x01(\r\x12\x16\n\x0eRenewWithUsage\x18\x0b \x01(\x08\x1a\xf9\t\n\x0cKeyContainer\x12\n\n\x02Id\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x12\x0b\n\x03Key\x18\x03 \x01(\x0c\x12+\n\x04Type\x18\x04 \x01(\x0e\x32\x1d.License.KeyContainer.KeyType\x12\x32\n\x05Level\x18\x05 \x01(\x0e\x32#.License.KeyContainer.SecurityLevel\x12\x42\n\x12RequiredProtection\x18\x06 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x43\n\x13RequestedProtection\x18\x07 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x35\n\x0b_KeyControl\x18\x08 \x01(\x0b\x32 .License.KeyContainer.KeyControl\x12[\n\x1e_OperatorSessionKeyPermissions\x18\t \x01(\x0b\x32\x33.License.KeyContainer.OperatorSessionKeyPermissions\x12S\n\x1aVideoResolutionConstraints\x18\n \x03(\x0b\x32/.License.KeyContainer.VideoResolutionConstraint\x1a\xdb\x01\n\x10OutputProtection\x12\x42\n\x04Hdcp\x18\x01 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12>\n\tCgmsFlags\x18\x02 \x01(\x0e\x32+.License.KeyContainer.OutputProtection.CGMS\"C\n\x04\x43GMS\x12\r\n\tCOPY_FREE\x10\x00\x12\r\n\tCOPY_ONCE\x10\x02\x12\x0e\n\nCOPY_NEVER\x10\x03\x12\r\n\tCGMS_NONE\x10*\x1a\x31\n\nKeyControl\x12\x17\n\x0fKeyControlBlock\x18\x01 \x02(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x1a|\n\x1dOperatorSessionKeyPermissions\x12\x14\n\x0c\x41llowEncrypt\x18\x01 \x01(\r\x12\x14\n\x0c\x41llowDecrypt\x18\x02 \x01(\r\x12\x11\n\tAllowSign\x18\x03 \x01(\r\x12\x1c\n\x14\x41llowSignatureVerify\x18\x04 \x01(\r\x1a\x99\x01\n\x19VideoResolutionConstraint\x12\x1b\n\x13MinResolutionPixels\x18\x01 \x01(\r\x12\x1b\n\x13MaxResolutionPixels\x18\x02 \x01(\r\x12\x42\n\x12RequiredProtection\x18\x03 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\"J\n\x07KeyType\x12\x0b\n\x07SIGNING\x10\x01\x12\x0b\n\x07\x43ONTENT\x10\x02\x12\x0f\n\x0bKEY_CONTROL\x10\x03\x12\x14\n\x10OPERATOR_SESSION\x10\x04\"z\n\rSecurityLevel\x12\x14\n\x10SW_SECURE_CRYPTO\x10\x01\x12\x14\n\x10SW_SECURE_DECODE\x10\x02\x12\x14\n\x10HW_SECURE_CRYPTO\x10\x03\x12\x14\n\x10HW_SECURE_DECODE\x10\x04\x12\x11\n\rHW_SECURE_ALL\x10\x05\"\x98\x01\n\x0cLicenseError\x12&\n\tErrorCode\x18\x01 \x01(\x0e\x32\x13.LicenseError.Error\"`\n\x05\x45rror\x12\x1e\n\x1aINVALID_DEVICE_CERTIFICATE\x10\x01\x12\x1e\n\x1aREVOKED_DEVICE_CERTIFICATE\x10\x02\x12\x17\n\x13SERVICE_UNAVAILABLE\x10\x03\"\xac\x07\n\x0eLicenseRequest\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12\x38\n\tContentId\x18\x02 \x01(\x0b\x32%.LicenseRequest.ContentIdentification\x12)\n\x04Type\x18\x03 \x01(\x0e\x32\x1b.LicenseRequest.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\xa2\x04\n\x15\x43ontentIdentification\x12:\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.CENC\x12:\n\x06WebmId\x18\x02 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.WebM\x12\x46\n\x07License\x18\x03 \x01(\x0b\x32\x35.LicenseRequest.ContentIdentification.ExistingLicense\x1a_\n\x04\x43\x45NC\x12!\n\x04Pssh\x18\x01 \x01(\x0b\x32\x13.WidevineCencHeader\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"0\n\x0bRequestType\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa9\x07\n\x11LicenseRequestRaw\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12;\n\tContentId\x18\x02 \x01(\x0b\x32(.LicenseRequestRaw.ContentIdentification\x12,\n\x04Type\x18\x03 \x01(\x0e\x32\x1e.LicenseRequestRaw.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\x96\x04\n\x15\x43ontentIdentification\x12=\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32-.LicenseRequestRaw.ContentIdentification.CENC\x12=\n\x06WebmId\x18\x02 \x01(\x0b\x32-.LicenseRequestRaw.ContentIdentification.WebM\x12I\n\x07License\x18\x03 \x01(\x0b\x32\x38.LicenseRequestRaw.ContentIdentification.ExistingLicense\x1aJ\n\x04\x43\x45NC\x12\x0c\n\x04Pssh\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"0\n\x0bRequestType\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa6\x02\n\x15ProvisionedDeviceInfo\x12\x10\n\x08SystemId\x18\x01 \x01(\r\x12\x0b\n\x03Soc\x18\x02 \x01(\t\x12\x14\n\x0cManufacturer\x18\x03 \x01(\t\x12\r\n\x05Model\x18\x04 \x01(\t\x12\x12\n\nDeviceType\x18\x05 \x01(\t\x12\x11\n\tModelYear\x18\x06 \x01(\r\x12=\n\rSecurityLevel\x18\x07 \x01(\x0e\x32&.ProvisionedDeviceInfo.WvSecurityLevel\x12\x12\n\nTestDevice\x18\x08 \x01(\r\"O\n\x0fWvSecurityLevel\x12\x15\n\x11LEVEL_UNSPECIFIED\x10\x00\x12\x0b\n\x07LEVEL_1\x10\x01\x12\x0b\n\x07LEVEL_2\x10\x02\x12\x0b\n\x07LEVEL_3\x10\x03\"\x15\n\x13ProvisioningOptions\"\x15\n\x13ProvisioningRequest\"\x16\n\x14ProvisioningResponse\"i\n\x11RemoteAttestation\x12\x33\n\x0b\x43\x65rtificate\x18\x01 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x12\x0c\n\x04Salt\x18\x02 \x01(\t\x12\x11\n\tSignature\x18\x03 \x01(\t\"\r\n\x0bSessionInit\"\x0e\n\x0cSessionState\"\x1d\n\x1bSignedCertificateStatusList\"\x86\x01\n\x17SignedDeviceCertificate\x12.\n\x12_DeviceCertificate\x18\x01 \x01(\x0b\x32\x12.DeviceCertificate\x12\x11\n\tSignature\x18\x02 \x01(\x0c\x12(\n\x06Signer\x18\x03 \x01(\x0b\x32\x18.SignedDeviceCertificate\"\x1b\n\x19SignedProvisioningMessage\"\x9b\x02\n\rSignedMessage\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedMessage.MessageType\x12\x0b\n\x03Msg\x18\x02 \x01(\x0c\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc5\x02\n\x12WidevineCencHeader\x12\x30\n\talgorithm\x18\x01 \x01(\x0e\x32\x1d.WidevineCencHeader.Algorithm\x12\x0e\n\x06key_id\x18\x02 \x03(\x0c\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x1d\n\x15track_type_deprecated\x18\x05 \x01(\t\x12\x0e\n\x06policy\x18\x06 \x01(\t\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x17\n\x0fgrouped_license\x18\x08 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\t \x01(\r\x12\x1d\n\x15\x63rypto_period_seconds\x18\n \x01(\r\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"\xba\x02\n\x14SignedLicenseRequest\x12/\n\x04Type\x18\x01 \x01(\x0e\x32!.SignedLicenseRequest.MessageType\x12\x1c\n\x03Msg\x18\x02 \x01(\x0b\x32\x0f.LicenseRequest\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc3\x02\n\x17SignedLicenseRequestRaw\x12\x32\n\x04Type\x18\x01 \x01(\x0e\x32$.SignedLicenseRequestRaw.MessageType\x12\x1f\n\x03Msg\x18\x02 \x01(\x0b\x32\x12.LicenseRequestRaw\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xa5\x02\n\rSignedLicense\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedLicense.MessageType\x12\x15\n\x03Msg\x18\x02 \x01(\x0b\x32\x08.License\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xcb\x02\n\x18SignedServiceCertificate\x12\x33\n\x04Type\x18\x01 \x01(\x0e\x32%.SignedServiceCertificate.MessageType\x12%\n\x03Msg\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"}\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xb5\x01\n\nFileHashes\x12\x0e\n\x06signer\x18\x01 \x01(\x0c\x12)\n\nsignatures\x18\x02 \x03(\x0b\x32\x15.FileHashes.Signature\x1al\n\tSignature\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x14\n\x0ctest_signing\x18\x02 \x01(\x08\x12\x12\n\nSHA512Hash\x18\x03 \x01(\x0c\x12\x10\n\x08main_exe\x18\x04 \x01(\x08\x12\x11\n\tsignature\x18\x05 \x01(\x0c*1\n\x0bLicenseType\x12\x08\n\x04ZERO\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01\x12\x0b\n\x07OFFLINE\x10\x02*\x1e\n\x0fProtocolVersion\x12\x0b\n\x07\x43URRENT\x10\x15') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wv_proto2_pb2', globals()) + +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _LICENSETYPE._serialized_start=8339 + _LICENSETYPE._serialized_end=8388 + _PROTOCOLVERSION._serialized_start=8390 + _PROTOCOLVERSION._serialized_end=8420 + _CLIENTIDENTIFICATION._serialized_start=20 + _CLIENTIDENTIFICATION._serialized_end=763 + _CLIENTIDENTIFICATION_NAMEVALUE._serialized_start=343 + _CLIENTIDENTIFICATION_NAMEVALUE._serialized_end=383 + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES._serialized_start=386 + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES._serialized_end=678 + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION._serialized_start=594 + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION._serialized_end=678 + _CLIENTIDENTIFICATION_TOKENTYPE._serialized_start=680 + _CLIENTIDENTIFICATION_TOKENTYPE._serialized_end=763 + _DEVICECERTIFICATE._serialized_start=766 + _DEVICECERTIFICATE._serialized_end=1049 + _DEVICECERTIFICATE_CERTIFICATETYPE._serialized_start=974 + _DEVICECERTIFICATE_CERTIFICATETYPE._serialized_end=1049 + _DEVICECERTIFICATESTATUS._serialized_start=1052 + _DEVICECERTIFICATESTATUS._serialized_end=1248 + _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS._serialized_start=1205 + _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS._serialized_end=1248 + _DEVICECERTIFICATESTATUSLIST._serialized_start=1250 + _DEVICECERTIFICATESTATUSLIST._serialized_end=1361 + _ENCRYPTEDCLIENTIDENTIFICATION._serialized_start=1364 + _ENCRYPTEDCLIENTIDENTIFICATION._serialized_end=1539 + _LICENSEIDENTIFICATION._serialized_start=1542 + _LICENSEIDENTIFICATION._serialized_end=1698 + _LICENSE._serialized_start=1701 + _LICENSE._serialized_end=3526 + _LICENSE_POLICY._serialized_start=1935 + _LICENSE_POLICY._serialized_end=2250 + _LICENSE_KEYCONTAINER._serialized_start=2253 + _LICENSE_KEYCONTAINER._serialized_end=3526 + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION._serialized_start=2774 + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION._serialized_end=2993 + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS._serialized_start=2926 + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS._serialized_end=2993 + _LICENSE_KEYCONTAINER_KEYCONTROL._serialized_start=2995 + _LICENSE_KEYCONTAINER_KEYCONTROL._serialized_end=3044 + _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS._serialized_start=3046 + _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS._serialized_end=3170 + _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT._serialized_start=3173 + _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT._serialized_end=3326 + _LICENSE_KEYCONTAINER_KEYTYPE._serialized_start=3328 + _LICENSE_KEYCONTAINER_KEYTYPE._serialized_end=3402 + _LICENSE_KEYCONTAINER_SECURITYLEVEL._serialized_start=3404 + _LICENSE_KEYCONTAINER_SECURITYLEVEL._serialized_end=3526 + _LICENSEERROR._serialized_start=3529 + _LICENSEERROR._serialized_end=3681 + _LICENSEERROR_ERROR._serialized_start=3585 + _LICENSEERROR_ERROR._serialized_end=3681 + _LICENSEREQUEST._serialized_start=3684 + _LICENSEREQUEST._serialized_end=4624 + _LICENSEREQUEST_CONTENTIDENTIFICATION._serialized_start=4028 + _LICENSEREQUEST_CONTENTIDENTIFICATION._serialized_end=4574 + _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC._serialized_start=4245 + _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC._serialized_end=4340 + _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM._serialized_start=4342 + _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM._serialized_end=4418 + _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE._serialized_start=4421 + _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE._serialized_end=4574 + _LICENSEREQUEST_REQUESTTYPE._serialized_start=4576 + _LICENSEREQUEST_REQUESTTYPE._serialized_end=4624 + _LICENSEREQUESTRAW._serialized_start=4627 + _LICENSEREQUESTRAW._serialized_end=5564 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION._serialized_start=4980 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION._serialized_end=5514 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC._serialized_start=5206 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC._serialized_end=5280 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM._serialized_start=4342 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM._serialized_end=4418 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE._serialized_start=4421 + _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE._serialized_end=4574 + _LICENSEREQUESTRAW_REQUESTTYPE._serialized_start=4576 + _LICENSEREQUESTRAW_REQUESTTYPE._serialized_end=4624 + _PROVISIONEDDEVICEINFO._serialized_start=5567 + _PROVISIONEDDEVICEINFO._serialized_end=5861 + _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL._serialized_start=5782 + _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL._serialized_end=5861 + _PROVISIONINGOPTIONS._serialized_start=5863 + _PROVISIONINGOPTIONS._serialized_end=5884 + _PROVISIONINGREQUEST._serialized_start=5886 + _PROVISIONINGREQUEST._serialized_end=5907 + _PROVISIONINGRESPONSE._serialized_start=5909 + _PROVISIONINGRESPONSE._serialized_end=5931 + _REMOTEATTESTATION._serialized_start=5933 + _REMOTEATTESTATION._serialized_end=6038 + _SESSIONINIT._serialized_start=6040 + _SESSIONINIT._serialized_end=6053 + _SESSIONSTATE._serialized_start=6055 + _SESSIONSTATE._serialized_end=6069 + _SIGNEDCERTIFICATESTATUSLIST._serialized_start=6071 + _SIGNEDCERTIFICATESTATUSLIST._serialized_end=6100 + _SIGNEDDEVICECERTIFICATE._serialized_start=6103 + _SIGNEDDEVICECERTIFICATE._serialized_end=6237 + _SIGNEDPROVISIONINGMESSAGE._serialized_start=6239 + _SIGNEDPROVISIONINGMESSAGE._serialized_end=6266 + _SIGNEDMESSAGE._serialized_start=6269 + _SIGNEDMESSAGE._serialized_end=6552 + _SIGNEDMESSAGE_MESSAGETYPE._serialized_start=6427 + _SIGNEDMESSAGE_MESSAGETYPE._serialized_end=6552 + _WIDEVINECENCHEADER._serialized_start=6555 + _WIDEVINECENCHEADER._serialized_end=6880 + _WIDEVINECENCHEADER_ALGORITHM._serialized_start=6840 + _WIDEVINECENCHEADER_ALGORITHM._serialized_end=6880 + _SIGNEDLICENSEREQUEST._serialized_start=6883 + _SIGNEDLICENSEREQUEST._serialized_end=7197 + _SIGNEDLICENSEREQUEST_MESSAGETYPE._serialized_start=6427 + _SIGNEDLICENSEREQUEST_MESSAGETYPE._serialized_end=6552 + _SIGNEDLICENSEREQUESTRAW._serialized_start=7200 + _SIGNEDLICENSEREQUESTRAW._serialized_end=7523 + _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE._serialized_start=6427 + _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE._serialized_end=6552 + _SIGNEDLICENSE._serialized_start=7526 + _SIGNEDLICENSE._serialized_end=7819 + _SIGNEDLICENSE_MESSAGETYPE._serialized_start=6427 + _SIGNEDLICENSE_MESSAGETYPE._serialized_end=6552 + _SIGNEDSERVICECERTIFICATE._serialized_start=7822 + _SIGNEDSERVICECERTIFICATE._serialized_end=8153 + _SIGNEDSERVICECERTIFICATE_MESSAGETYPE._serialized_start=6427 + _SIGNEDSERVICECERTIFICATE_MESSAGETYPE._serialized_end=6552 + _FILEHASHES._serialized_start=8156 + _FILEHASHES._serialized_end=8337 + _FILEHASHES_SIGNATURE._serialized_start=8229 + _FILEHASHES_SIGNATURE._serialized_end=8337 +# @@protoc_insertion_point(module_scope) diff --git a/utils/widevine/formats/wv_proto3.proto b/utils/widevine/formats/wv_proto3.proto new file mode 100644 index 0000000..9e2e4a4 --- /dev/null +++ b/utils/widevine/formats/wv_proto3.proto @@ -0,0 +1,389 @@ +// beware proto3 won't show missing fields it seems, need to change to "proto2" and add "optional" before every field, and remove all the dummy enum members I added: +syntax = "proto3"; + +// from x86 (partial), most of it from the ARM version: +message ClientIdentification { + enum TokenType { + KEYBOX = 0; + DEVICE_CERTIFICATE = 1; + REMOTE_ATTESTATION_CERTIFICATE = 2; + } + message NameValue { + string Name = 1; + string Value = 2; + } + message ClientCapabilities { + enum HdcpVersion { + HDCP_NONE = 0; + HDCP_V1 = 1; + HDCP_V2 = 2; + HDCP_V2_1 = 3; + HDCP_V2_2 = 4; + } + uint32 ClientToken = 1; + uint32 SessionToken = 2; + uint32 VideoResolutionConstraints = 3; + HdcpVersion MaxHdcpVersion = 4; + uint32 OemCryptoApiVersion = 5; + } + TokenType Type = 1; + //bytes Token = 2; // by default the client treats this as blob, but it's usually a DeviceCertificate, so for usefulness sake, I'm replacing it with this one: + SignedDeviceCertificate Token = 2; + repeated NameValue ClientInfo = 3; + bytes ProviderClientToken = 4; + uint32 LicenseCounter = 5; + ClientCapabilities _ClientCapabilities = 6; // how should we deal with duped names? will have to look at proto docs later +} + +message DeviceCertificate { + enum CertificateType { + ROOT = 0; + INTERMEDIATE = 1; + USER_DEVICE = 2; + SERVICE = 3; + } + //ProvisionedDeviceInfo.WvSecurityLevel Type = 1; // is this how one is supposed to call it? (it's an enum) there might be a bug here, with CertificateType getting confused with WvSecurityLevel, for now renaming it (verify against other binaries) + CertificateType Type = 1; + bytes SerialNumber = 2; + uint32 CreationTimeSeconds = 3; + bytes PublicKey = 4; + uint32 SystemId = 5; + uint32 TestDeviceDeprecated = 6; // is it bool or int? + bytes ServiceId = 7; // service URL for service certificates +} + +// missing some references, +message DeviceCertificateStatus { + enum CertificateStatus { + VALID = 0; + REVOKED = 1; + } + bytes SerialNumber = 1; + CertificateStatus Status = 2; + ProvisionedDeviceInfo DeviceInfo = 4; // where is 3? is it deprecated? +} + +message DeviceCertificateStatusList { + uint32 CreationTimeSeconds = 1; + repeated DeviceCertificateStatus CertificateStatus = 2; +} + +message EncryptedClientIdentification { + string ServiceId = 1; + bytes ServiceCertificateSerialNumber = 2; + bytes EncryptedClientId = 3; + bytes EncryptedClientIdIv = 4; + bytes EncryptedPrivacyKey = 5; +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +enum LicenseType { + ZERO = 0; + DEFAULT = 1; // do not know what this is either, but should be 1; on recent versions may go up to 3 (latest x86) +} + +// todo: fill (for this top-level type, it might be impossible/difficult) +// this is just a guess because these globals got lost, but really, do we need more? +enum ProtocolVersion { + DUMMY = 0; + CURRENT = 21; // don't have symbols for this +} + + +message LicenseIdentification { + bytes RequestId = 1; + bytes SessionId = 2; + bytes PurchaseId = 3; + LicenseType Type = 4; + uint32 Version = 5; + bytes ProviderSessionToken = 6; +} + + +message License { + message Policy { + uint32 CanPlay = 1; + uint32 CanPersist = 2; + uint32 CanRenew = 3; + uint32 RentalDurationSeconds = 4; + uint32 PlaybackDurationSeconds = 5; + uint32 LicenseDurationSeconds = 6; + uint32 RenewalRecoveryDurationSeconds = 7; + string RenewalServerUrl = 8; + uint32 RenewalDelaySeconds = 9; + uint32 RenewalRetryIntervalSeconds = 10; + uint32 RenewWithUsage = 11; + uint32 UnknownPolicy12 = 12; + } + message KeyContainer { + enum KeyType { + _NOKEYTYPE = 0; // dummy, added to satisfy proto3, not present in original + SIGNING = 1; + CONTENT = 2; + KEY_CONTROL = 3; + OPERATOR_SESSION = 4; + } + enum SecurityLevel { + _NOSECLEVEL = 0; // dummy, added to satisfy proto3, not present in original + SW_SECURE_CRYPTO = 1; + SW_SECURE_DECODE = 2; + HW_SECURE_CRYPTO = 3; + HW_SECURE_DECODE = 4; + HW_SECURE_ALL = 5; + } + message OutputProtection { + enum CGMS { + COPY_FREE = 0; + COPY_ONCE = 2; + COPY_NEVER = 3; + CGMS_NONE = 0x2A; // PC default! + } + ClientIdentification.ClientCapabilities.HdcpVersion Hdcp = 1; // it's most likely a copy of Hdcp version available here, but compiler optimized it away + CGMS CgmsFlags = 2; + } + message KeyControl { + bytes KeyControlBlock = 1; // what is this? + bytes Iv = 2; + } + message OperatorSessionKeyPermissions { + uint32 AllowEncrypt = 1; + uint32 AllowDecrypt = 2; + uint32 AllowSign = 3; + uint32 AllowSignatureVerify = 4; + } + message VideoResolutionConstraint { + uint32 MinResolutionPixels = 1; + uint32 MaxResolutionPixels = 2; + OutputProtection RequiredProtection = 3; + } + bytes Id = 1; + bytes Iv = 2; + bytes Key = 3; + KeyType Type = 4; + SecurityLevel Level = 5; + OutputProtection RequiredProtection = 6; + OutputProtection RequestedProtection = 7; + KeyControl _KeyControl = 8; // duped names, etc + OperatorSessionKeyPermissions _OperatorSessionKeyPermissions = 9; // duped names, etc + repeated VideoResolutionConstraint VideoResolutionConstraints = 10; + } + LicenseIdentification Id = 1; + Policy _Policy = 2; // duped names, etc + repeated KeyContainer Key = 3; + uint32 LicenseStartTime = 4; + uint32 RemoteAttestationVerified = 5; // bool? + bytes ProviderClientToken = 6; + // there might be more, check with newer versions (I see field 7-8 in a lic) + // this appeared in latest x86: + uint32 ProtectionScheme = 7; // type unconfirmed fully, but it's likely as WidevineCencHeader describesit (fourcc) + bytes UnknownHdcpDataField = 8; +} + +message LicenseError { + enum Error { + DUMMY_NO_ERROR = 0; // dummy, added to satisfy proto3 + INVALID_DEVICE_CERTIFICATE = 1; + REVOKED_DEVICE_CERTIFICATE = 2; + SERVICE_UNAVAILABLE = 3; + } + //LicenseRequest.RequestType ErrorCode; // clang mismatch + Error ErrorCode = 1; +} + +message LicenseRequest { + message ContentIdentification { + message CENC { + // bytes Pssh = 1; // the client's definition is opaque, it doesn't care about the contents, but the PSSH has a clear definition that is understood and requested by the server, thus I'll replace it with: + WidevineCencHeader Pssh = 1; + LicenseType LicenseType = 2; // unfortunately the LicenseType symbols are not present, acceptable value seems to only be 1 + bytes RequestId = 3; + } + message WebM { + bytes Header = 1; // identical to CENC, aside from PSSH and the parent field number used + LicenseType LicenseType = 2; + bytes RequestId = 3; + } + message ExistingLicense { + LicenseIdentification LicenseId = 1; + uint32 SecondsSinceStarted = 2; + uint32 SecondsSinceLastPlayed = 3; + bytes SessionUsageTableEntry = 4; + } + CENC CencId = 1; + WebM WebmId = 2; + ExistingLicense License = 3; + } + enum RequestType { + DUMMY_REQ_TYPE = 0; // dummy, added to satisfy proto3 + NEW = 1; + RENEWAL = 2; + RELEASE = 3; + } + ClientIdentification ClientId = 1; + ContentIdentification ContentId = 2; + RequestType Type = 3; + uint32 RequestTime = 4; + bytes KeyControlNonceDeprecated = 5; + ProtocolVersion ProtocolVersion = 6; // lacking symbols for this + uint32 KeyControlNonce = 7; + EncryptedClientIdentification EncryptedClientId = 8; +} + +message ProvisionedDeviceInfo { + enum WvSecurityLevel { + LEVEL_UNSPECIFIED = 0; + LEVEL_1 = 1; + LEVEL_2 = 2; + LEVEL_3 = 3; + } + uint32 SystemId = 1; + string Soc = 2; + string Manufacturer = 3; + string Model = 4; + string DeviceType = 5; + uint32 ModelYear = 6; + WvSecurityLevel SecurityLevel = 7; + uint32 TestDevice = 8; // bool? +} + + +// todo: fill +message ProvisioningOptions { +} + +// todo: fill +message ProvisioningRequest { +} + +// todo: fill +message ProvisioningResponse { +} + +message RemoteAttestation { + EncryptedClientIdentification Certificate = 1; + string Salt = 2; + string Signature = 3; +} + +// todo: fill +message SessionInit { +} + +// todo: fill +message SessionState { +} + +// todo: fill +message SignedCertificateStatusList { +} + +message SignedDeviceCertificate { + + //bytes DeviceCertificate = 1; // again, they use a buffer where it's supposed to be a message, so we'll replace it with what it really is: + DeviceCertificate _DeviceCertificate = 1; // how should we deal with duped names? will have to look at proto docs later + bytes Signature = 2; + SignedDeviceCertificate Signer = 3; +} + + +// todo: fill +message SignedProvisioningMessage { +} + +// the root of all messages, from either server or client +message SignedMessage { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + bytes Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} + + + +// This message is copied from google's docs, not reversed: +message WidevineCencHeader { + enum Algorithm { + UNENCRYPTED = 0; + AESCTR = 1; + }; + Algorithm algorithm = 1; + repeated bytes key_id = 2; + + // Content provider name. + string provider = 3; + + // A content identifier, specified by content provider. + bytes content_id = 4; + + // Track type. Acceptable values are SD, HD and AUDIO. Used to + // differentiate content keys used by an asset. + string track_type_deprecated = 5; + + // The name of a registered policy to be used for this asset. + string policy = 6; + + // Crypto period index, for media using key rotation. + uint32 crypto_period_index = 7; + + // Optional protected context for group content. The grouped_license is a + // serialized SignedMessage. + bytes grouped_license = 8; + + // Protection scheme identifying the encryption algorithm. + // Represented as one of the following 4CC values: + // 'cenc' (AESCTR), 'cbc1' (AESCBC), + // 'cens' (AESCTR subsample), 'cbcs' (AESCBC subsample). + uint32 protection_scheme = 9; + + // Optional. For media using key rotation, this represents the duration + // of each crypto period in seconds. + uint32 crypto_period_seconds = 10; +} + + + + +// from here on, it's just for testing, these messages don't exist in the binaries, I'm adding them to avoid detecting type programmatically +message SignedLicenseRequest { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + LicenseRequest Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} + +message SignedLicense { + enum MessageType { + DUMMY_MSG_TYPE = 0; // dummy, added to satisfy proto3 + LICENSE_REQUEST = 1; + LICENSE = 2; + ERROR_RESPONSE = 3; + SERVICE_CERTIFICATE_REQUEST = 4; + SERVICE_CERTIFICATE = 5; + } + MessageType Type = 1; // has in incorrect overlap with License_KeyContainer_SecurityLevel + License Msg = 2; // this has to be casted dynamically, to LicenseRequest, License or LicenseError (? unconfirmed), for Request, no other fields but Type need to be present + // for SERVICE_CERTIFICATE, only Type and Msg are present, and it's just a DeviceCertificate with CertificateType set to SERVICE + bytes Signature = 3; // might be different type of signatures (ex. RSA vs AES CMAC(??), unconfirmed for now) + bytes SessionKey = 4; // often RSA wrapped for licenses + RemoteAttestation RemoteAttestation = 5; +} \ No newline at end of file diff --git a/utils/widevine/formats/wv_proto3_pb2.py b/utils/widevine/formats/wv_proto3_pb2.py new file mode 100644 index 0000000..5b9da3b --- /dev/null +++ b/utils/widevine/formats/wv_proto3_pb2.py @@ -0,0 +1,2684 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: wv_proto3.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) + +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + +DESCRIPTOR = _descriptor.FileDescriptor( + name='wv_proto3.proto', + package='', + syntax='proto3', + serialized_pb=_b('\n\x0fwv_proto3.proto\"\xc5\x05\n\x14\x43lientIdentification\x12-\n\x04Type\x18\x01 \x01(\x0e\x32\x1f.ClientIdentification.TokenType\x12\'\n\x05Token\x18\x02 \x01(\x0b\x32\x18.SignedDeviceCertificate\x12\x33\n\nClientInfo\x18\x03 \x03(\x0b\x32\x1f.ClientIdentification.NameValue\x12\x1b\n\x13ProviderClientToken\x18\x04 \x01(\x0c\x12\x16\n\x0eLicenseCounter\x18\x05 \x01(\r\x12\x45\n\x13_ClientCapabilities\x18\x06 \x01(\x0b\x32(.ClientIdentification.ClientCapabilities\x1a(\n\tNameValue\x12\x0c\n\x04Name\x18\x01 \x01(\t\x12\r\n\x05Value\x18\x02 \x01(\t\x1a\xa4\x02\n\x12\x43lientCapabilities\x12\x13\n\x0b\x43lientToken\x18\x01 \x01(\r\x12\x14\n\x0cSessionToken\x18\x02 \x01(\r\x12\"\n\x1aVideoResolutionConstraints\x18\x03 \x01(\r\x12L\n\x0eMaxHdcpVersion\x18\x04 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12\x1b\n\x13OemCryptoApiVersion\x18\x05 \x01(\r\"T\n\x0bHdcpVersion\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\"S\n\tTokenType\x12\n\n\x06KEYBOX\x10\x00\x12\x16\n\x12\x44\x45VICE_CERTIFICATE\x10\x01\x12\"\n\x1eREMOTE_ATTESTATION_CERTIFICATE\x10\x02\"\x9b\x02\n\x11\x44\x65viceCertificate\x12\x30\n\x04Type\x18\x01 \x01(\x0e\x32\".DeviceCertificate.CertificateType\x12\x14\n\x0cSerialNumber\x18\x02 \x01(\x0c\x12\x1b\n\x13\x43reationTimeSeconds\x18\x03 \x01(\r\x12\x11\n\tPublicKey\x18\x04 \x01(\x0c\x12\x10\n\x08SystemId\x18\x05 \x01(\r\x12\x1c\n\x14TestDeviceDeprecated\x18\x06 \x01(\r\x12\x11\n\tServiceId\x18\x07 \x01(\x0c\"K\n\x0f\x43\x65rtificateType\x12\x08\n\x04ROOT\x10\x00\x12\x10\n\x0cINTERMEDIATE\x10\x01\x12\x0f\n\x0bUSER_DEVICE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\"\xc4\x01\n\x17\x44\x65viceCertificateStatus\x12\x14\n\x0cSerialNumber\x18\x01 \x01(\x0c\x12:\n\x06Status\x18\x02 \x01(\x0e\x32*.DeviceCertificateStatus.CertificateStatus\x12*\n\nDeviceInfo\x18\x04 \x01(\x0b\x32\x16.ProvisionedDeviceInfo\"+\n\x11\x43\x65rtificateStatus\x12\t\n\x05VALID\x10\x00\x12\x0b\n\x07REVOKED\x10\x01\"o\n\x1b\x44\x65viceCertificateStatusList\x12\x1b\n\x13\x43reationTimeSeconds\x18\x01 \x01(\r\x12\x33\n\x11\x43\x65rtificateStatus\x18\x02 \x03(\x0b\x32\x18.DeviceCertificateStatus\"\xaf\x01\n\x1d\x45ncryptedClientIdentification\x12\x11\n\tServiceId\x18\x01 \x01(\t\x12&\n\x1eServiceCertificateSerialNumber\x18\x02 \x01(\x0c\x12\x19\n\x11\x45ncryptedClientId\x18\x03 \x01(\x0c\x12\x1b\n\x13\x45ncryptedClientIdIv\x18\x04 \x01(\x0c\x12\x1b\n\x13\x45ncryptedPrivacyKey\x18\x05 \x01(\x0c\"\x9c\x01\n\x15LicenseIdentification\x12\x11\n\tRequestId\x18\x01 \x01(\x0c\x12\x11\n\tSessionId\x18\x02 \x01(\x0c\x12\x12\n\nPurchaseId\x18\x03 \x01(\x0c\x12\x1a\n\x04Type\x18\x04 \x01(\x0e\x32\x0c.LicenseType\x12\x0f\n\x07Version\x18\x05 \x01(\r\x12\x1c\n\x14ProviderSessionToken\x18\x06 \x01(\x0c\"\xfa\x0e\n\x07License\x12\"\n\x02Id\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12 \n\x07_Policy\x18\x02 \x01(\x0b\x32\x0f.License.Policy\x12\"\n\x03Key\x18\x03 \x03(\x0b\x32\x15.License.KeyContainer\x12\x18\n\x10LicenseStartTime\x18\x04 \x01(\r\x12!\n\x19RemoteAttestationVerified\x18\x05 \x01(\r\x12\x1b\n\x13ProviderClientToken\x18\x06 \x01(\x0c\x12\x18\n\x10ProtectionScheme\x18\x07 \x01(\r\x12\x1c\n\x14UnknownHdcpDataField\x18\x08 \x01(\x0c\x1a\xd4\x02\n\x06Policy\x12\x0f\n\x07\x43\x61nPlay\x18\x01 \x01(\r\x12\x12\n\nCanPersist\x18\x02 \x01(\r\x12\x10\n\x08\x43\x61nRenew\x18\x03 \x01(\r\x12\x1d\n\x15RentalDurationSeconds\x18\x04 \x01(\r\x12\x1f\n\x17PlaybackDurationSeconds\x18\x05 \x01(\r\x12\x1e\n\x16LicenseDurationSeconds\x18\x06 \x01(\r\x12&\n\x1eRenewalRecoveryDurationSeconds\x18\x07 \x01(\r\x12\x18\n\x10RenewalServerUrl\x18\x08 \x01(\t\x12\x1b\n\x13RenewalDelaySeconds\x18\t \x01(\r\x12#\n\x1bRenewalRetryIntervalSeconds\x18\n \x01(\r\x12\x16\n\x0eRenewWithUsage\x18\x0b \x01(\r\x12\x17\n\x0fUnknownPolicy12\x18\x0c \x01(\r\x1a\x9b\n\n\x0cKeyContainer\x12\n\n\x02Id\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x12\x0b\n\x03Key\x18\x03 \x01(\x0c\x12+\n\x04Type\x18\x04 \x01(\x0e\x32\x1d.License.KeyContainer.KeyType\x12\x32\n\x05Level\x18\x05 \x01(\x0e\x32#.License.KeyContainer.SecurityLevel\x12\x42\n\x12RequiredProtection\x18\x06 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x43\n\x13RequestedProtection\x18\x07 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\x12\x35\n\x0b_KeyControl\x18\x08 \x01(\x0b\x32 .License.KeyContainer.KeyControl\x12[\n\x1e_OperatorSessionKeyPermissions\x18\t \x01(\x0b\x32\x33.License.KeyContainer.OperatorSessionKeyPermissions\x12S\n\x1aVideoResolutionConstraints\x18\n \x03(\x0b\x32/.License.KeyContainer.VideoResolutionConstraint\x1a\xdb\x01\n\x10OutputProtection\x12\x42\n\x04Hdcp\x18\x01 \x01(\x0e\x32\x34.ClientIdentification.ClientCapabilities.HdcpVersion\x12>\n\tCgmsFlags\x18\x02 \x01(\x0e\x32+.License.KeyContainer.OutputProtection.CGMS\"C\n\x04\x43GMS\x12\r\n\tCOPY_FREE\x10\x00\x12\r\n\tCOPY_ONCE\x10\x02\x12\x0e\n\nCOPY_NEVER\x10\x03\x12\r\n\tCGMS_NONE\x10*\x1a\x31\n\nKeyControl\x12\x17\n\x0fKeyControlBlock\x18\x01 \x01(\x0c\x12\n\n\x02Iv\x18\x02 \x01(\x0c\x1a|\n\x1dOperatorSessionKeyPermissions\x12\x14\n\x0c\x41llowEncrypt\x18\x01 \x01(\r\x12\x14\n\x0c\x41llowDecrypt\x18\x02 \x01(\r\x12\x11\n\tAllowSign\x18\x03 \x01(\r\x12\x1c\n\x14\x41llowSignatureVerify\x18\x04 \x01(\r\x1a\x99\x01\n\x19VideoResolutionConstraint\x12\x1b\n\x13MinResolutionPixels\x18\x01 \x01(\r\x12\x1b\n\x13MaxResolutionPixels\x18\x02 \x01(\r\x12\x42\n\x12RequiredProtection\x18\x03 \x01(\x0b\x32&.License.KeyContainer.OutputProtection\"Z\n\x07KeyType\x12\x0e\n\n_NOKEYTYPE\x10\x00\x12\x0b\n\x07SIGNING\x10\x01\x12\x0b\n\x07\x43ONTENT\x10\x02\x12\x0f\n\x0bKEY_CONTROL\x10\x03\x12\x14\n\x10OPERATOR_SESSION\x10\x04\"\x8b\x01\n\rSecurityLevel\x12\x0f\n\x0b_NOSECLEVEL\x10\x00\x12\x14\n\x10SW_SECURE_CRYPTO\x10\x01\x12\x14\n\x10SW_SECURE_DECODE\x10\x02\x12\x14\n\x10HW_SECURE_CRYPTO\x10\x03\x12\x14\n\x10HW_SECURE_DECODE\x10\x04\x12\x11\n\rHW_SECURE_ALL\x10\x05\"\xac\x01\n\x0cLicenseError\x12&\n\tErrorCode\x18\x01 \x01(\x0e\x32\x13.LicenseError.Error\"t\n\x05\x45rror\x12\x12\n\x0e\x44UMMY_NO_ERROR\x10\x00\x12\x1e\n\x1aINVALID_DEVICE_CERTIFICATE\x10\x01\x12\x1e\n\x1aREVOKED_DEVICE_CERTIFICATE\x10\x02\x12\x17\n\x13SERVICE_UNAVAILABLE\x10\x03\"\xc0\x07\n\x0eLicenseRequest\x12\'\n\x08\x43lientId\x18\x01 \x01(\x0b\x32\x15.ClientIdentification\x12\x38\n\tContentId\x18\x02 \x01(\x0b\x32%.LicenseRequest.ContentIdentification\x12)\n\x04Type\x18\x03 \x01(\x0e\x32\x1b.LicenseRequest.RequestType\x12\x13\n\x0bRequestTime\x18\x04 \x01(\r\x12!\n\x19KeyControlNonceDeprecated\x18\x05 \x01(\x0c\x12)\n\x0fProtocolVersion\x18\x06 \x01(\x0e\x32\x10.ProtocolVersion\x12\x17\n\x0fKeyControlNonce\x18\x07 \x01(\r\x12\x39\n\x11\x45ncryptedClientId\x18\x08 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x1a\xa2\x04\n\x15\x43ontentIdentification\x12:\n\x06\x43\x65ncId\x18\x01 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.CENC\x12:\n\x06WebmId\x18\x02 \x01(\x0b\x32*.LicenseRequest.ContentIdentification.WebM\x12\x46\n\x07License\x18\x03 \x01(\x0b\x32\x35.LicenseRequest.ContentIdentification.ExistingLicense\x1a_\n\x04\x43\x45NC\x12!\n\x04Pssh\x18\x01 \x01(\x0b\x32\x13.WidevineCencHeader\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1aL\n\x04WebM\x12\x0e\n\x06Header\x18\x01 \x01(\x0c\x12!\n\x0bLicenseType\x18\x02 \x01(\x0e\x32\x0c.LicenseType\x12\x11\n\tRequestId\x18\x03 \x01(\x0c\x1a\x99\x01\n\x0f\x45xistingLicense\x12)\n\tLicenseId\x18\x01 \x01(\x0b\x32\x16.LicenseIdentification\x12\x1b\n\x13SecondsSinceStarted\x18\x02 \x01(\r\x12\x1e\n\x16SecondsSinceLastPlayed\x18\x03 \x01(\r\x12\x1e\n\x16SessionUsageTableEntry\x18\x04 \x01(\x0c\"D\n\x0bRequestType\x12\x12\n\x0e\x44UMMY_REQ_TYPE\x10\x00\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xa6\x02\n\x15ProvisionedDeviceInfo\x12\x10\n\x08SystemId\x18\x01 \x01(\r\x12\x0b\n\x03Soc\x18\x02 \x01(\t\x12\x14\n\x0cManufacturer\x18\x03 \x01(\t\x12\r\n\x05Model\x18\x04 \x01(\t\x12\x12\n\nDeviceType\x18\x05 \x01(\t\x12\x11\n\tModelYear\x18\x06 \x01(\r\x12=\n\rSecurityLevel\x18\x07 \x01(\x0e\x32&.ProvisionedDeviceInfo.WvSecurityLevel\x12\x12\n\nTestDevice\x18\x08 \x01(\r\"O\n\x0fWvSecurityLevel\x12\x15\n\x11LEVEL_UNSPECIFIED\x10\x00\x12\x0b\n\x07LEVEL_1\x10\x01\x12\x0b\n\x07LEVEL_2\x10\x02\x12\x0b\n\x07LEVEL_3\x10\x03\"\x15\n\x13ProvisioningOptions\"\x15\n\x13ProvisioningRequest\"\x16\n\x14ProvisioningResponse\"i\n\x11RemoteAttestation\x12\x33\n\x0b\x43\x65rtificate\x18\x01 \x01(\x0b\x32\x1e.EncryptedClientIdentification\x12\x0c\n\x04Salt\x18\x02 \x01(\t\x12\x11\n\tSignature\x18\x03 \x01(\t\"\r\n\x0bSessionInit\"\x0e\n\x0cSessionState\"\x1d\n\x1bSignedCertificateStatusList\"\x86\x01\n\x17SignedDeviceCertificate\x12.\n\x12_DeviceCertificate\x18\x01 \x01(\x0b\x32\x12.DeviceCertificate\x12\x11\n\tSignature\x18\x02 \x01(\x0c\x12(\n\x06Signer\x18\x03 \x01(\x0b\x32\x18.SignedDeviceCertificate\"\x1b\n\x19SignedProvisioningMessage\"\xb0\x02\n\rSignedMessage\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedMessage.MessageType\x12\x0b\n\x03Msg\x18\x02 \x01(\x0c\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xc5\x02\n\x12WidevineCencHeader\x12\x30\n\talgorithm\x18\x01 \x01(\x0e\x32\x1d.WidevineCencHeader.Algorithm\x12\x0e\n\x06key_id\x18\x02 \x03(\x0c\x12\x10\n\x08provider\x18\x03 \x01(\t\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x1d\n\x15track_type_deprecated\x18\x05 \x01(\t\x12\x0e\n\x06policy\x18\x06 \x01(\t\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x17\n\x0fgrouped_license\x18\x08 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\t \x01(\r\x12\x1d\n\x15\x63rypto_period_seconds\x18\n \x01(\r\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"\xcf\x02\n\x14SignedLicenseRequest\x12/\n\x04Type\x18\x01 \x01(\x0e\x32!.SignedLicenseRequest.MessageType\x12\x1c\n\x03Msg\x18\x02 \x01(\x0b\x32\x0f.LicenseRequest\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\"\xba\x02\n\rSignedLicense\x12(\n\x04Type\x18\x01 \x01(\x0e\x32\x1a.SignedLicense.MessageType\x12\x15\n\x03Msg\x18\x02 \x01(\x0b\x32\x08.License\x12\x11\n\tSignature\x18\x03 \x01(\x0c\x12\x12\n\nSessionKey\x18\x04 \x01(\x0c\x12-\n\x11RemoteAttestation\x18\x05 \x01(\x0b\x32\x12.RemoteAttestation\"\x91\x01\n\x0bMessageType\x12\x12\n\x0e\x44UMMY_MSG_TYPE\x10\x00\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05*$\n\x0bLicenseType\x12\x08\n\x04ZERO\x10\x00\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x01*)\n\x0fProtocolVersion\x12\t\n\x05\x44UMMY\x10\x00\x12\x0b\n\x07\x43URRENT\x10\x15\x62\x06proto3') +) + +_LICENSETYPE = _descriptor.EnumDescriptor( + name='LicenseType', + full_name='LicenseType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ZERO', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEFAULT', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6713, + serialized_end=6749, +) +_sym_db.RegisterEnumDescriptor(_LICENSETYPE) + +LicenseType = enum_type_wrapper.EnumTypeWrapper(_LICENSETYPE) +_PROTOCOLVERSION = _descriptor.EnumDescriptor( + name='ProtocolVersion', + full_name='ProtocolVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CURRENT', index=1, number=21, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6751, + serialized_end=6792, +) +_sym_db.RegisterEnumDescriptor(_PROTOCOLVERSION) + +ProtocolVersion = enum_type_wrapper.EnumTypeWrapper(_PROTOCOLVERSION) +ZERO = 0 +DEFAULT = 1 +DUMMY = 0 +CURRENT = 21 + + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION = _descriptor.EnumDescriptor( + name='HdcpVersion', + full_name='ClientIdentification.ClientCapabilities.HdcpVersion', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='HDCP_NONE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_1', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HDCP_V2_2', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=560, + serialized_end=644, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION) + +_CLIENTIDENTIFICATION_TOKENTYPE = _descriptor.EnumDescriptor( + name='TokenType', + full_name='ClientIdentification.TokenType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='KEYBOX', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='DEVICE_CERTIFICATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REMOTE_ATTESTATION_CERTIFICATE', index=2, number=2, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=646, + serialized_end=729, +) +_sym_db.RegisterEnumDescriptor(_CLIENTIDENTIFICATION_TOKENTYPE) + +_DEVICECERTIFICATE_CERTIFICATETYPE = _descriptor.EnumDescriptor( + name='CertificateType', + full_name='DeviceCertificate.CertificateType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='ROOT', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INTERMEDIATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='USER_DEVICE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=940, + serialized_end=1015, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATE_CERTIFICATETYPE) + +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS = _descriptor.EnumDescriptor( + name='CertificateStatus', + full_name='DeviceCertificateStatus.CertificateStatus', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='VALID', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=1171, + serialized_end=1214, +) +_sym_db.RegisterEnumDescriptor(_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS = _descriptor.EnumDescriptor( + name='CGMS', + full_name='License.KeyContainer.OutputProtection.CGMS', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='COPY_FREE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_ONCE', index=1, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='COPY_NEVER', index=2, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CGMS_NONE', index=3, number=42, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=2947, + serialized_end=3014, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS) + +_LICENSE_KEYCONTAINER_KEYTYPE = _descriptor.EnumDescriptor( + name='KeyType', + full_name='License.KeyContainer.KeyType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='_NOKEYTYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SIGNING', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CONTENT', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='KEY_CONTROL', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='OPERATOR_SESSION', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3349, + serialized_end=3439, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_KEYTYPE) + +_LICENSE_KEYCONTAINER_SECURITYLEVEL = _descriptor.EnumDescriptor( + name='SecurityLevel', + full_name='License.KeyContainer.SecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='_NOSECLEVEL', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SW_SECURE_CRYPTO', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SW_SECURE_DECODE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_CRYPTO', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_DECODE', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='HW_SECURE_ALL', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3442, + serialized_end=3581, +) +_sym_db.RegisterEnumDescriptor(_LICENSE_KEYCONTAINER_SECURITYLEVEL) + +_LICENSEERROR_ERROR = _descriptor.EnumDescriptor( + name='Error', + full_name='LicenseError.Error', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_NO_ERROR', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='INVALID_DEVICE_CERTIFICATE', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='REVOKED_DEVICE_CERTIFICATE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_UNAVAILABLE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=3640, + serialized_end=3756, +) +_sym_db.RegisterEnumDescriptor(_LICENSEERROR_ERROR) + +_LICENSEREQUEST_REQUESTTYPE = _descriptor.EnumDescriptor( + name='RequestType', + full_name='LicenseRequest.RequestType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_REQ_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='NEW', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RENEWAL', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='RELEASE', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4651, + serialized_end=4719, +) +_sym_db.RegisterEnumDescriptor(_LICENSEREQUEST_REQUESTTYPE) + +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL = _descriptor.EnumDescriptor( + name='WvSecurityLevel', + full_name='ProvisionedDeviceInfo.WvSecurityLevel', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='LEVEL_UNSPECIFIED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_1', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_2', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LEVEL_3', index=3, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=4937, + serialized_end=5016, +) +_sym_db.RegisterEnumDescriptor(_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL) + +_SIGNEDMESSAGE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedMessage.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDMESSAGE_MESSAGETYPE) + +_WIDEVINECENCHEADER_ALGORITHM = _descriptor.EnumDescriptor( + name='Algorithm', + full_name='WidevineCencHeader.Algorithm', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='UNENCRYPTED', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='AESCTR', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=6016, + serialized_end=6056, +) +_sym_db.RegisterEnumDescriptor(_WIDEVINECENCHEADER_ALGORITHM) + +_SIGNEDLICENSEREQUEST_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicenseRequest.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUEST_MESSAGETYPE) + +_SIGNEDLICENSE_MESSAGETYPE = _descriptor.EnumDescriptor( + name='MessageType', + full_name='SignedLicense.MessageType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='DUMMY_MSG_TYPE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE_REQUEST', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LICENSE', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ERROR_RESPONSE', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE_REQUEST', index=4, number=4, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SERVICE_CERTIFICATE', index=5, number=5, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=5583, + serialized_end=5728, +) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSE_MESSAGETYPE) + + +_CLIENTIDENTIFICATION_NAMEVALUE = _descriptor.Descriptor( + name='NameValue', + full_name='ClientIdentification.NameValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Name', full_name='ClientIdentification.NameValue.Name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Value', full_name='ClientIdentification.NameValue.Value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=309, + serialized_end=349, +) + +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES = _descriptor.Descriptor( + name='ClientCapabilities', + full_name='ClientIdentification.ClientCapabilities', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientToken', full_name='ClientIdentification.ClientCapabilities.ClientToken', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionToken', full_name='ClientIdentification.ClientCapabilities.SessionToken', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='ClientIdentification.ClientCapabilities.VideoResolutionConstraints', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxHdcpVersion', full_name='ClientIdentification.ClientCapabilities.MaxHdcpVersion', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='OemCryptoApiVersion', full_name='ClientIdentification.ClientCapabilities.OemCryptoApiVersion', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=352, + serialized_end=644, +) + +_CLIENTIDENTIFICATION = _descriptor.Descriptor( + name='ClientIdentification', + full_name='ClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='ClientIdentification.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Token', full_name='ClientIdentification.Token', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ClientInfo', full_name='ClientIdentification.ClientInfo', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='ClientIdentification.ProviderClientToken', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseCounter', full_name='ClientIdentification.LicenseCounter', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_ClientCapabilities', full_name='ClientIdentification._ClientCapabilities', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_CLIENTIDENTIFICATION_NAMEVALUE, _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, ], + enum_types=[ + _CLIENTIDENTIFICATION_TOKENTYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=20, + serialized_end=729, +) + + +_DEVICECERTIFICATE = _descriptor.Descriptor( + name='DeviceCertificate', + full_name='DeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='DeviceCertificate.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificate.SerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificate.CreationTimeSeconds', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PublicKey', full_name='DeviceCertificate.PublicKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SystemId', full_name='DeviceCertificate.SystemId', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDeviceDeprecated', full_name='DeviceCertificate.TestDeviceDeprecated', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceId', full_name='DeviceCertificate.ServiceId', index=6, + number=7, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATE_CERTIFICATETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=732, + serialized_end=1015, +) + + +_DEVICECERTIFICATESTATUS = _descriptor.Descriptor( + name='DeviceCertificateStatus', + full_name='DeviceCertificateStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SerialNumber', full_name='DeviceCertificateStatus.SerialNumber', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Status', full_name='DeviceCertificateStatus.Status', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceInfo', full_name='DeviceCertificateStatus.DeviceInfo', index=2, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1018, + serialized_end=1214, +) + + +_DEVICECERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='DeviceCertificateStatusList', + full_name='DeviceCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CreationTimeSeconds', full_name='DeviceCertificateStatusList.CreationTimeSeconds', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CertificateStatus', full_name='DeviceCertificateStatusList.CertificateStatus', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1216, + serialized_end=1327, +) + + +_ENCRYPTEDCLIENTIDENTIFICATION = _descriptor.Descriptor( + name='EncryptedClientIdentification', + full_name='EncryptedClientIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ServiceId', full_name='EncryptedClientIdentification.ServiceId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ServiceCertificateSerialNumber', full_name='EncryptedClientIdentification.ServiceCertificateSerialNumber', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='EncryptedClientIdentification.EncryptedClientId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientIdIv', full_name='EncryptedClientIdentification.EncryptedClientIdIv', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedPrivacyKey', full_name='EncryptedClientIdentification.EncryptedPrivacyKey', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1330, + serialized_end=1505, +) + + +_LICENSEIDENTIFICATION = _descriptor.Descriptor( + name='LicenseIdentification', + full_name='LicenseIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseIdentification.RequestId', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionId', full_name='LicenseIdentification.SessionId', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PurchaseId', full_name='LicenseIdentification.PurchaseId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseIdentification.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Version', full_name='LicenseIdentification.Version', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderSessionToken', full_name='LicenseIdentification.ProviderSessionToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1508, + serialized_end=1664, +) + + +_LICENSE_POLICY = _descriptor.Descriptor( + name='Policy', + full_name='License.Policy', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CanPlay', full_name='License.Policy.CanPlay', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanPersist', full_name='License.Policy.CanPersist', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CanRenew', full_name='License.Policy.CanRenew', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RentalDurationSeconds', full_name='License.Policy.RentalDurationSeconds', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='PlaybackDurationSeconds', full_name='License.Policy.PlaybackDurationSeconds', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseDurationSeconds', full_name='License.Policy.LicenseDurationSeconds', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRecoveryDurationSeconds', full_name='License.Policy.RenewalRecoveryDurationSeconds', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalServerUrl', full_name='License.Policy.RenewalServerUrl', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalDelaySeconds', full_name='License.Policy.RenewalDelaySeconds', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewalRetryIntervalSeconds', full_name='License.Policy.RenewalRetryIntervalSeconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RenewWithUsage', full_name='License.Policy.RenewWithUsage', index=10, + number=11, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='UnknownPolicy12', full_name='License.Policy.UnknownPolicy12', index=11, + number=12, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1931, + serialized_end=2271, +) + +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION = _descriptor.Descriptor( + name='OutputProtection', + full_name='License.KeyContainer.OutputProtection', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Hdcp', full_name='License.KeyContainer.OutputProtection.Hdcp', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='CgmsFlags', full_name='License.KeyContainer.OutputProtection.CgmsFlags', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2795, + serialized_end=3014, +) + +_LICENSE_KEYCONTAINER_KEYCONTROL = _descriptor.Descriptor( + name='KeyControl', + full_name='License.KeyContainer.KeyControl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='KeyControlBlock', full_name='License.KeyContainer.KeyControl.KeyControlBlock', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.KeyControl.Iv', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3016, + serialized_end=3065, +) + +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS = _descriptor.Descriptor( + name='OperatorSessionKeyPermissions', + full_name='License.KeyContainer.OperatorSessionKeyPermissions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='AllowEncrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowEncrypt', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowDecrypt', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowDecrypt', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSign', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSign', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='AllowSignatureVerify', full_name='License.KeyContainer.OperatorSessionKeyPermissions.AllowSignatureVerify', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3067, + serialized_end=3191, +) + +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT = _descriptor.Descriptor( + name='VideoResolutionConstraint', + full_name='License.KeyContainer.VideoResolutionConstraint', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='MinResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MinResolutionPixels', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='MaxResolutionPixels', full_name='License.KeyContainer.VideoResolutionConstraint.MaxResolutionPixels', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.VideoResolutionConstraint.RequiredProtection', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3194, + serialized_end=3347, +) + +_LICENSE_KEYCONTAINER = _descriptor.Descriptor( + name='KeyContainer', + full_name='License.KeyContainer', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.KeyContainer.Id', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Iv', full_name='License.KeyContainer.Iv', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.KeyContainer.Key', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='License.KeyContainer.Type', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Level', full_name='License.KeyContainer.Level', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequiredProtection', full_name='License.KeyContainer.RequiredProtection', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestedProtection', full_name='License.KeyContainer.RequestedProtection', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_KeyControl', full_name='License.KeyContainer._KeyControl', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_OperatorSessionKeyPermissions', full_name='License.KeyContainer._OperatorSessionKeyPermissions', index=8, + number=9, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='VideoResolutionConstraints', full_name='License.KeyContainer.VideoResolutionConstraints', index=9, + number=10, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_KEYCONTAINER_OUTPUTPROTECTION, _LICENSE_KEYCONTAINER_KEYCONTROL, _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, ], + enum_types=[ + _LICENSE_KEYCONTAINER_KEYTYPE, + _LICENSE_KEYCONTAINER_SECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2274, + serialized_end=3581, +) + +_LICENSE = _descriptor.Descriptor( + name='License', + full_name='License', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Id', full_name='License.Id', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='_Policy', full_name='License._Policy', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Key', full_name='License.Key', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseStartTime', full_name='License.LicenseStartTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestationVerified', full_name='License.RemoteAttestationVerified', index=4, + number=5, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProviderClientToken', full_name='License.ProviderClientToken', index=5, + number=6, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtectionScheme', full_name='License.ProtectionScheme', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='UnknownHdcpDataField', full_name='License.UnknownHdcpDataField', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSE_POLICY, _LICENSE_KEYCONTAINER, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1667, + serialized_end=3581, +) + + +_LICENSEERROR = _descriptor.Descriptor( + name='LicenseError', + full_name='LicenseError', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ErrorCode', full_name='LicenseError.ErrorCode', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _LICENSEERROR_ERROR, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3584, + serialized_end=3756, +) + + +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC = _descriptor.Descriptor( + name='CENC', + full_name='LicenseRequest.ContentIdentification.CENC', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Pssh', full_name='LicenseRequest.ContentIdentification.CENC.Pssh', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.CENC.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.CENC.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4320, + serialized_end=4415, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM = _descriptor.Descriptor( + name='WebM', + full_name='LicenseRequest.ContentIdentification.WebM', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Header', full_name='LicenseRequest.ContentIdentification.WebM.Header', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='LicenseType', full_name='LicenseRequest.ContentIdentification.WebM.LicenseType', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestId', full_name='LicenseRequest.ContentIdentification.WebM.RequestId', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4417, + serialized_end=4493, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE = _descriptor.Descriptor( + name='ExistingLicense', + full_name='LicenseRequest.ContentIdentification.ExistingLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='LicenseId', full_name='LicenseRequest.ContentIdentification.ExistingLicense.LicenseId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceStarted', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceStarted', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecondsSinceLastPlayed', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SecondsSinceLastPlayed', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionUsageTableEntry', full_name='LicenseRequest.ContentIdentification.ExistingLicense.SessionUsageTableEntry', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4496, + serialized_end=4649, +) + +_LICENSEREQUEST_CONTENTIDENTIFICATION = _descriptor.Descriptor( + name='ContentIdentification', + full_name='LicenseRequest.ContentIdentification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='CencId', full_name='LicenseRequest.ContentIdentification.CencId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='WebmId', full_name='LicenseRequest.ContentIdentification.WebmId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='License', full_name='LicenseRequest.ContentIdentification.License', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, ], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4103, + serialized_end=4649, +) + +_LICENSEREQUEST = _descriptor.Descriptor( + name='LicenseRequest', + full_name='LicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ClientId', full_name='LicenseRequest.ClientId', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ContentId', full_name='LicenseRequest.ContentId', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Type', full_name='LicenseRequest.Type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RequestTime', full_name='LicenseRequest.RequestTime', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonceDeprecated', full_name='LicenseRequest.KeyControlNonceDeprecated', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ProtocolVersion', full_name='LicenseRequest.ProtocolVersion', index=5, + number=6, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='KeyControlNonce', full_name='LicenseRequest.KeyControlNonce', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='EncryptedClientId', full_name='LicenseRequest.EncryptedClientId', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[_LICENSEREQUEST_CONTENTIDENTIFICATION, ], + enum_types=[ + _LICENSEREQUEST_REQUESTTYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3759, + serialized_end=4719, +) + + +_PROVISIONEDDEVICEINFO = _descriptor.Descriptor( + name='ProvisionedDeviceInfo', + full_name='ProvisionedDeviceInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='SystemId', full_name='ProvisionedDeviceInfo.SystemId', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Soc', full_name='ProvisionedDeviceInfo.Soc', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Manufacturer', full_name='ProvisionedDeviceInfo.Manufacturer', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Model', full_name='ProvisionedDeviceInfo.Model', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='DeviceType', full_name='ProvisionedDeviceInfo.DeviceType', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='ModelYear', full_name='ProvisionedDeviceInfo.ModelYear', index=5, + number=6, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SecurityLevel', full_name='ProvisionedDeviceInfo.SecurityLevel', index=6, + number=7, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='TestDevice', full_name='ProvisionedDeviceInfo.TestDevice', index=7, + number=8, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4722, + serialized_end=5016, +) + + +_PROVISIONINGOPTIONS = _descriptor.Descriptor( + name='ProvisioningOptions', + full_name='ProvisioningOptions', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5018, + serialized_end=5039, +) + + +_PROVISIONINGREQUEST = _descriptor.Descriptor( + name='ProvisioningRequest', + full_name='ProvisioningRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5041, + serialized_end=5062, +) + + +_PROVISIONINGRESPONSE = _descriptor.Descriptor( + name='ProvisioningResponse', + full_name='ProvisioningResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5064, + serialized_end=5086, +) + + +_REMOTEATTESTATION = _descriptor.Descriptor( + name='RemoteAttestation', + full_name='RemoteAttestation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Certificate', full_name='RemoteAttestation.Certificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Salt', full_name='RemoteAttestation.Salt', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='RemoteAttestation.Signature', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5088, + serialized_end=5193, +) + + +_SESSIONINIT = _descriptor.Descriptor( + name='SessionInit', + full_name='SessionInit', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5195, + serialized_end=5208, +) + + +_SESSIONSTATE = _descriptor.Descriptor( + name='SessionState', + full_name='SessionState', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5210, + serialized_end=5224, +) + + +_SIGNEDCERTIFICATESTATUSLIST = _descriptor.Descriptor( + name='SignedCertificateStatusList', + full_name='SignedCertificateStatusList', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5226, + serialized_end=5255, +) + + +_SIGNEDDEVICECERTIFICATE = _descriptor.Descriptor( + name='SignedDeviceCertificate', + full_name='SignedDeviceCertificate', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='_DeviceCertificate', full_name='SignedDeviceCertificate._DeviceCertificate', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedDeviceCertificate.Signature', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signer', full_name='SignedDeviceCertificate.Signer', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5258, + serialized_end=5392, +) + + +_SIGNEDPROVISIONINGMESSAGE = _descriptor.Descriptor( + name='SignedProvisioningMessage', + full_name='SignedProvisioningMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5394, + serialized_end=5421, +) + + +_SIGNEDMESSAGE = _descriptor.Descriptor( + name='SignedMessage', + full_name='SignedMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedMessage.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedMessage.Msg', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedMessage.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedMessage.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedMessage.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDMESSAGE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5424, + serialized_end=5728, +) + + +_WIDEVINECENCHEADER = _descriptor.Descriptor( + name='WidevineCencHeader', + full_name='WidevineCencHeader', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='algorithm', full_name='WidevineCencHeader.algorithm', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='key_id', full_name='WidevineCencHeader.key_id', index=1, + number=2, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='provider', full_name='WidevineCencHeader.provider', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content_id', full_name='WidevineCencHeader.content_id', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='track_type_deprecated', full_name='WidevineCencHeader.track_type_deprecated', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='policy', full_name='WidevineCencHeader.policy', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_index', full_name='WidevineCencHeader.crypto_period_index', index=6, + number=7, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='grouped_license', full_name='WidevineCencHeader.grouped_license', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='protection_scheme', full_name='WidevineCencHeader.protection_scheme', index=8, + number=9, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='crypto_period_seconds', full_name='WidevineCencHeader.crypto_period_seconds', index=9, + number=10, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _WIDEVINECENCHEADER_ALGORITHM, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=5731, + serialized_end=6056, +) + + +_SIGNEDLICENSEREQUEST = _descriptor.Descriptor( + name='SignedLicenseRequest', + full_name='SignedLicenseRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicenseRequest.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicenseRequest.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicenseRequest.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicenseRequest.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicenseRequest.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSEREQUEST_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6059, + serialized_end=6394, +) + + +_SIGNEDLICENSE = _descriptor.Descriptor( + name='SignedLicense', + full_name='SignedLicense', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Type', full_name='SignedLicense.Type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Msg', full_name='SignedLicense.Msg', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='Signature', full_name='SignedLicense.Signature', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='SessionKey', full_name='SignedLicense.SessionKey', index=3, + number=4, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='RemoteAttestation', full_name='SignedLicense.RemoteAttestation', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNEDLICENSE_MESSAGETYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=6397, + serialized_end=6711, +) + +_CLIENTIDENTIFICATION_NAMEVALUE.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.fields_by_name['MaxHdcpVersion'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES.containing_type = _CLIENTIDENTIFICATION +_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION.containing_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION.fields_by_name['Type'].enum_type = _CLIENTIDENTIFICATION_TOKENTYPE +_CLIENTIDENTIFICATION.fields_by_name['Token'].message_type = _SIGNEDDEVICECERTIFICATE +_CLIENTIDENTIFICATION.fields_by_name['ClientInfo'].message_type = _CLIENTIDENTIFICATION_NAMEVALUE +_CLIENTIDENTIFICATION.fields_by_name['_ClientCapabilities'].message_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES +_CLIENTIDENTIFICATION_TOKENTYPE.containing_type = _CLIENTIDENTIFICATION +_DEVICECERTIFICATE.fields_by_name['Type'].enum_type = _DEVICECERTIFICATE_CERTIFICATETYPE +_DEVICECERTIFICATE_CERTIFICATETYPE.containing_type = _DEVICECERTIFICATE +_DEVICECERTIFICATESTATUS.fields_by_name['Status'].enum_type = _DEVICECERTIFICATESTATUS_CERTIFICATESTATUS +_DEVICECERTIFICATESTATUS.fields_by_name['DeviceInfo'].message_type = _PROVISIONEDDEVICEINFO +_DEVICECERTIFICATESTATUS_CERTIFICATESTATUS.containing_type = _DEVICECERTIFICATESTATUS +_DEVICECERTIFICATESTATUSLIST.fields_by_name['CertificateStatus'].message_type = _DEVICECERTIFICATESTATUS +_LICENSEIDENTIFICATION.fields_by_name['Type'].enum_type = _LICENSETYPE +_LICENSE_POLICY.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['Hdcp'].enum_type = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.fields_by_name['CgmsFlags'].enum_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS.containing_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_KEYCONTROL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER.fields_by_name['Type'].enum_type = _LICENSE_KEYCONTAINER_KEYTYPE +_LICENSE_KEYCONTAINER.fields_by_name['Level'].enum_type = _LICENSE_KEYCONTAINER_SECURITYLEVEL +_LICENSE_KEYCONTAINER.fields_by_name['RequiredProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['RequestedProtection'].message_type = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION +_LICENSE_KEYCONTAINER.fields_by_name['_KeyControl'].message_type = _LICENSE_KEYCONTAINER_KEYCONTROL +_LICENSE_KEYCONTAINER.fields_by_name['_OperatorSessionKeyPermissions'].message_type = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS +_LICENSE_KEYCONTAINER.fields_by_name['VideoResolutionConstraints'].message_type = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT +_LICENSE_KEYCONTAINER.containing_type = _LICENSE +_LICENSE_KEYCONTAINER_KEYTYPE.containing_type = _LICENSE_KEYCONTAINER +_LICENSE_KEYCONTAINER_SECURITYLEVEL.containing_type = _LICENSE_KEYCONTAINER +_LICENSE.fields_by_name['Id'].message_type = _LICENSEIDENTIFICATION +_LICENSE.fields_by_name['_Policy'].message_type = _LICENSE_POLICY +_LICENSE.fields_by_name['Key'].message_type = _LICENSE_KEYCONTAINER +_LICENSEERROR.fields_by_name['ErrorCode'].enum_type = _LICENSEERROR_ERROR +_LICENSEERROR_ERROR.containing_type = _LICENSEERROR +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['Pssh'].message_type = _WIDEVINECENCHEADER +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_CENC.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.fields_by_name['LicenseType'].enum_type = _LICENSETYPE +_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.fields_by_name['LicenseId'].message_type = _LICENSEIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE.containing_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['CencId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['WebmId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM +_LICENSEREQUEST_CONTENTIDENTIFICATION.fields_by_name['License'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE +_LICENSEREQUEST_CONTENTIDENTIFICATION.containing_type = _LICENSEREQUEST +_LICENSEREQUEST.fields_by_name['ClientId'].message_type = _CLIENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['ContentId'].message_type = _LICENSEREQUEST_CONTENTIDENTIFICATION +_LICENSEREQUEST.fields_by_name['Type'].enum_type = _LICENSEREQUEST_REQUESTTYPE +_LICENSEREQUEST.fields_by_name['ProtocolVersion'].enum_type = _PROTOCOLVERSION +_LICENSEREQUEST.fields_by_name['EncryptedClientId'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_LICENSEREQUEST_REQUESTTYPE.containing_type = _LICENSEREQUEST +_PROVISIONEDDEVICEINFO.fields_by_name['SecurityLevel'].enum_type = _PROVISIONEDDEVICEINFO_WVSECURITYLEVEL +_PROVISIONEDDEVICEINFO_WVSECURITYLEVEL.containing_type = _PROVISIONEDDEVICEINFO +_REMOTEATTESTATION.fields_by_name['Certificate'].message_type = _ENCRYPTEDCLIENTIDENTIFICATION +_SIGNEDDEVICECERTIFICATE.fields_by_name['_DeviceCertificate'].message_type = _DEVICECERTIFICATE +_SIGNEDDEVICECERTIFICATE.fields_by_name['Signer'].message_type = _SIGNEDDEVICECERTIFICATE +_SIGNEDMESSAGE.fields_by_name['Type'].enum_type = _SIGNEDMESSAGE_MESSAGETYPE +_SIGNEDMESSAGE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDMESSAGE_MESSAGETYPE.containing_type = _SIGNEDMESSAGE +_WIDEVINECENCHEADER.fields_by_name['algorithm'].enum_type = _WIDEVINECENCHEADER_ALGORITHM +_WIDEVINECENCHEADER_ALGORITHM.containing_type = _WIDEVINECENCHEADER +_SIGNEDLICENSEREQUEST.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUEST_MESSAGETYPE +_SIGNEDLICENSEREQUEST.fields_by_name['Msg'].message_type = _LICENSEREQUEST +_SIGNEDLICENSEREQUEST.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSEREQUEST_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUEST +_SIGNEDLICENSE.fields_by_name['Type'].enum_type = _SIGNEDLICENSE_MESSAGETYPE +_SIGNEDLICENSE.fields_by_name['Msg'].message_type = _LICENSE +_SIGNEDLICENSE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION +_SIGNEDLICENSE_MESSAGETYPE.containing_type = _SIGNEDLICENSE +DESCRIPTOR.message_types_by_name['ClientIdentification'] = _CLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['DeviceCertificate'] = _DEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['DeviceCertificateStatus'] = _DEVICECERTIFICATESTATUS +DESCRIPTOR.message_types_by_name['DeviceCertificateStatusList'] = _DEVICECERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['EncryptedClientIdentification'] = _ENCRYPTEDCLIENTIDENTIFICATION +DESCRIPTOR.message_types_by_name['LicenseIdentification'] = _LICENSEIDENTIFICATION +DESCRIPTOR.message_types_by_name['License'] = _LICENSE +DESCRIPTOR.message_types_by_name['LicenseError'] = _LICENSEERROR +DESCRIPTOR.message_types_by_name['LicenseRequest'] = _LICENSEREQUEST +DESCRIPTOR.message_types_by_name['ProvisionedDeviceInfo'] = _PROVISIONEDDEVICEINFO +DESCRIPTOR.message_types_by_name['ProvisioningOptions'] = _PROVISIONINGOPTIONS +DESCRIPTOR.message_types_by_name['ProvisioningRequest'] = _PROVISIONINGREQUEST +DESCRIPTOR.message_types_by_name['ProvisioningResponse'] = _PROVISIONINGRESPONSE +DESCRIPTOR.message_types_by_name['RemoteAttestation'] = _REMOTEATTESTATION +DESCRIPTOR.message_types_by_name['SessionInit'] = _SESSIONINIT +DESCRIPTOR.message_types_by_name['SessionState'] = _SESSIONSTATE +DESCRIPTOR.message_types_by_name['SignedCertificateStatusList'] = _SIGNEDCERTIFICATESTATUSLIST +DESCRIPTOR.message_types_by_name['SignedDeviceCertificate'] = _SIGNEDDEVICECERTIFICATE +DESCRIPTOR.message_types_by_name['SignedProvisioningMessage'] = _SIGNEDPROVISIONINGMESSAGE +DESCRIPTOR.message_types_by_name['SignedMessage'] = _SIGNEDMESSAGE +DESCRIPTOR.message_types_by_name['WidevineCencHeader'] = _WIDEVINECENCHEADER +DESCRIPTOR.message_types_by_name['SignedLicenseRequest'] = _SIGNEDLICENSEREQUEST +DESCRIPTOR.message_types_by_name['SignedLicense'] = _SIGNEDLICENSE +DESCRIPTOR.enum_types_by_name['LicenseType'] = _LICENSETYPE +DESCRIPTOR.enum_types_by_name['ProtocolVersion'] = _PROTOCOLVERSION +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ClientIdentification = _reflection.GeneratedProtocolMessageType('ClientIdentification', (_message.Message,), dict( + + NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_NAMEVALUE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.NameValue) + )) + , + + ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (_message.Message,), dict( + DESCRIPTOR = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification.ClientCapabilities) + )) + , + DESCRIPTOR = _CLIENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ClientIdentification) + )) +_sym_db.RegisterMessage(ClientIdentification) +_sym_db.RegisterMessage(ClientIdentification.NameValue) +_sym_db.RegisterMessage(ClientIdentification.ClientCapabilities) + +DeviceCertificate = _reflection.GeneratedProtocolMessageType('DeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificate) + )) +_sym_db.RegisterMessage(DeviceCertificate) + +DeviceCertificateStatus = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatus', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatus) + )) +_sym_db.RegisterMessage(DeviceCertificateStatus) + +DeviceCertificateStatusList = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _DEVICECERTIFICATESTATUSLIST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:DeviceCertificateStatusList) + )) +_sym_db.RegisterMessage(DeviceCertificateStatusList) + +EncryptedClientIdentification = _reflection.GeneratedProtocolMessageType('EncryptedClientIdentification', (_message.Message,), dict( + DESCRIPTOR = _ENCRYPTEDCLIENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:EncryptedClientIdentification) + )) +_sym_db.RegisterMessage(EncryptedClientIdentification) + +LicenseIdentification = _reflection.GeneratedProtocolMessageType('LicenseIdentification', (_message.Message,), dict( + DESCRIPTOR = _LICENSEIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseIdentification) + )) +_sym_db.RegisterMessage(LicenseIdentification) + +License = _reflection.GeneratedProtocolMessageType('License', (_message.Message,), dict( + + Policy = _reflection.GeneratedProtocolMessageType('Policy', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_POLICY, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.Policy) + )) + , + + KeyContainer = _reflection.GeneratedProtocolMessageType('KeyContainer', (_message.Message,), dict( + + OutputProtection = _reflection.GeneratedProtocolMessageType('OutputProtection', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OutputProtection) + )) + , + + KeyControl = _reflection.GeneratedProtocolMessageType('KeyControl', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_KEYCONTROL, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.KeyControl) + )) + , + + OperatorSessionKeyPermissions = _reflection.GeneratedProtocolMessageType('OperatorSessionKeyPermissions', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.OperatorSessionKeyPermissions) + )) + , + + VideoResolutionConstraint = _reflection.GeneratedProtocolMessageType('VideoResolutionConstraint', (_message.Message,), dict( + DESCRIPTOR = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer.VideoResolutionConstraint) + )) + , + DESCRIPTOR = _LICENSE_KEYCONTAINER, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License.KeyContainer) + )) + , + DESCRIPTOR = _LICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:License) + )) +_sym_db.RegisterMessage(License) +_sym_db.RegisterMessage(License.Policy) +_sym_db.RegisterMessage(License.KeyContainer) +_sym_db.RegisterMessage(License.KeyContainer.OutputProtection) +_sym_db.RegisterMessage(License.KeyContainer.KeyControl) +_sym_db.RegisterMessage(License.KeyContainer.OperatorSessionKeyPermissions) +_sym_db.RegisterMessage(License.KeyContainer.VideoResolutionConstraint) + +LicenseError = _reflection.GeneratedProtocolMessageType('LicenseError', (_message.Message,), dict( + DESCRIPTOR = _LICENSEERROR, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseError) + )) +_sym_db.RegisterMessage(LicenseError) + +LicenseRequest = _reflection.GeneratedProtocolMessageType('LicenseRequest', (_message.Message,), dict( + + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( + + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.CENC) + )) + , + + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.WebM) + )) + , + + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.ExistingLicense) + )) + , + DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification) + )) + , + DESCRIPTOR = _LICENSEREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:LicenseRequest) + )) +_sym_db.RegisterMessage(LicenseRequest) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.CENC) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.WebM) +_sym_db.RegisterMessage(LicenseRequest.ContentIdentification.ExistingLicense) + +ProvisionedDeviceInfo = _reflection.GeneratedProtocolMessageType('ProvisionedDeviceInfo', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONEDDEVICEINFO, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisionedDeviceInfo) + )) +_sym_db.RegisterMessage(ProvisionedDeviceInfo) + +ProvisioningOptions = _reflection.GeneratedProtocolMessageType('ProvisioningOptions', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGOPTIONS, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningOptions) + )) +_sym_db.RegisterMessage(ProvisioningOptions) + +ProvisioningRequest = _reflection.GeneratedProtocolMessageType('ProvisioningRequest', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningRequest) + )) +_sym_db.RegisterMessage(ProvisioningRequest) + +ProvisioningResponse = _reflection.GeneratedProtocolMessageType('ProvisioningResponse', (_message.Message,), dict( + DESCRIPTOR = _PROVISIONINGRESPONSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:ProvisioningResponse) + )) +_sym_db.RegisterMessage(ProvisioningResponse) + +RemoteAttestation = _reflection.GeneratedProtocolMessageType('RemoteAttestation', (_message.Message,), dict( + DESCRIPTOR = _REMOTEATTESTATION, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:RemoteAttestation) + )) +_sym_db.RegisterMessage(RemoteAttestation) + +SessionInit = _reflection.GeneratedProtocolMessageType('SessionInit', (_message.Message,), dict( + DESCRIPTOR = _SESSIONINIT, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SessionInit) + )) +_sym_db.RegisterMessage(SessionInit) + +SessionState = _reflection.GeneratedProtocolMessageType('SessionState', (_message.Message,), dict( + DESCRIPTOR = _SESSIONSTATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SessionState) + )) +_sym_db.RegisterMessage(SessionState) + +SignedCertificateStatusList = _reflection.GeneratedProtocolMessageType('SignedCertificateStatusList', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDCERTIFICATESTATUSLIST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedCertificateStatusList) + )) +_sym_db.RegisterMessage(SignedCertificateStatusList) + +SignedDeviceCertificate = _reflection.GeneratedProtocolMessageType('SignedDeviceCertificate', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDDEVICECERTIFICATE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedDeviceCertificate) + )) +_sym_db.RegisterMessage(SignedDeviceCertificate) + +SignedProvisioningMessage = _reflection.GeneratedProtocolMessageType('SignedProvisioningMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDPROVISIONINGMESSAGE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedProvisioningMessage) + )) +_sym_db.RegisterMessage(SignedProvisioningMessage) + +SignedMessage = _reflection.GeneratedProtocolMessageType('SignedMessage', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDMESSAGE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedMessage) + )) +_sym_db.RegisterMessage(SignedMessage) + +WidevineCencHeader = _reflection.GeneratedProtocolMessageType('WidevineCencHeader', (_message.Message,), dict( + DESCRIPTOR = _WIDEVINECENCHEADER, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:WidevineCencHeader) + )) +_sym_db.RegisterMessage(WidevineCencHeader) + +SignedLicenseRequest = _reflection.GeneratedProtocolMessageType('SignedLicenseRequest', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSEREQUEST, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedLicenseRequest) + )) +_sym_db.RegisterMessage(SignedLicenseRequest) + +SignedLicense = _reflection.GeneratedProtocolMessageType('SignedLicense', (_message.Message,), dict( + DESCRIPTOR = _SIGNEDLICENSE, + __module__ = 'wv_proto3_pb2' + # @@protoc_insertion_point(class_scope:SignedLicense) + )) +_sym_db.RegisterMessage(SignedLicense) + + +# @@protoc_insertion_point(module_scope) diff --git a/utils/widevine/widevine.py b/utils/widevine/widevine.py new file mode 100644 index 0000000..6a03d2f --- /dev/null +++ b/utils/widevine/widevine.py @@ -0,0 +1,61 @@ +import base64 + +from utils.widevine.cdm import Device +from utils.widevine.cdm import ContentDecryptionModule + +class Widevine: + + WidevineSystemId = [237, 239, 139, 169, 121, 214, 74, 206, 163, 200, 39, 220, 213, 29, 33, 237] + + def __init__(self, init_data, cert_data, device_name, device_path): + self.initData = init_data + self.certData = cert_data + self.deviceName = device_name + self.devicePath = device_path + + self.cdm = ContentDecryptionModule() + + def checkPssh(b64Pssh): + pssh = base64.b64decode(b64Pssh) + if not pssh[12:28] == bytes(self.WidevineSystemId): + newPssh = bytearray([0, 0, 0]) + newPssh.append(32 + len(pssh)) + newPssh[4:] = bytearray(b'pssh') + newPssh[8:] = [0, 0, 0, 0] + newPssh[13:] = self.WidevineSystemId + newPssh[29:] = [0, 0, 0, 0] + newPssh[31] = len(pssh) + newPssh[32:] = pssh + + return base64.b64encode(newPssh) + else: + return b64Pssh + + self.session = self.cdm.open( + checkPssh(self.initData), + Device(self.deviceName, self.devicePath) + ) + + if self.certData: + self.cdm.setServiceCertificate(self.session, self.certData) + + def get_keys(self): + decryptKeys = [] + + try: + for key in self.cdm.getKeys(self.session): + if key.type == 'CONTENT': + decryptKeys.append( + '{}:{}'.format( + key.kid.hex(), + key.key.hex() + ) + ) + + except Exception: + return None + + return decryptKeys + + def get_challenge(self): return self.cdm.getLicenseRequest(self.session) + def update_license(self, b64License): self.cdm.provideLicense(self.session, b64License) \ No newline at end of file