VideoHelp Forum





Try StreamFab Downloader and download streaming video from Netflix, Amazon!



+ Reply to Thread
Results 1 to 4 of 4
  1. Hi,
    Can you please help me extract the keys for this Widevine DRM?

    PSSH:
    Code:
    AAAAUnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADIiKnZkb2NpcGhlcjo1NzYzZjQ3MTA4YTk0NWRkYjQ1ODZiYzhhMWQ3ZWRhYUjj3JWbBg==
    MPD:
    Code:
    https://cdn03.vdocipher.com/media/6Wvk0HD0SPBT6/168e94a9/stream.mpd
    KID:
    Code:
        7c10c1ed97345cf094f918c54db5962d: "usable",
        8ef81023898854918c9a8b72861999fe: "usable",
        c02a0ad7f6f25ea78a695efe29b9d673: "usable",
        f1f7264ec34e5112a158f744ea7426fb: "usable",
    licence :
    Code:
    https://license64.vdocipher.com/auth
    Headers:
    HTML Code:
    POST https://license64.vdocipher.com/auth HTTP/2
    host: license64.vdocipher.com
    content-length: 388
    vdo-sdk: VdoWeb/2.6.11
    sec-ch-ua-platform: "Windows"
    sec-ch-ua: "Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"
    sec-ch-ua-mobile: ?0
    cmcd-object: ot=k
    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36
    cmcd-session: cid="3bded3b626764b1bb08dc8a1d6c4dbbd",sf=d,sid="1b9f038067844818b7532f9191c744b4"
    cmcd-request: mtp=1500,su
    content-type: application/json
    accept: */*
    origin: https://player.vdocipher.com
    sec-fetch-site: same-site
    sec-fetch-mode: cors
    sec-fetch-dest: empty
    referer: https://player.vdocipher.com/
    accept-encoding: gzip, deflate, br, zstd
    accept-language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
    priority: u=1, i
    thanks in advance ..
    Image Attached Files
    Quote Quote  
  2. Here is the URL for the video: https://www.vdocipher.com/blog/2014/12/add-text-to-videos-with-watermark/

    Go to the page source code and search for encrypted-media; you will find the video URL at the top in src.
    Image
    [Attachment 92108 - Click to enlarge]


    My Python code, but it's in French:
    Code:
    import base64
    import json
    import re
    import sys
    from urllib.parse import urlparse, parse_qs
    
    import requests
    from bs4 import BeautifulSoup
    from pywidevine.device import Device
    from pywidevine.pssh import PSSH
    from pywidevine.cdm import Cdm
    
    
    # ================= CONFIG =================
    WVD_PATH = "device.wvd"
    TIMEOUT = 10
    RESET = "\033[0m"
    DEBUG = "\033[96m"   # bleu ciel (cyan clair)
    INFO = "\033[93m"    # jaune
    SUCCESS = "\033[92m" # vert
    KEY = "\033[94m"     # bleu
    ERROR = "\033[91m"   # rouge
    
    
    # ================= UTILS =================
    def erreur(msg):
        print(f"\n{ERROR}[ERREUR] {msg}{RESET}")
        sys.exit(1)
    
    
    def requete(method, url, **kwargs):
        try:
            r = requests.request(method, url, timeout=TIMEOUT, **kwargs)
            r.raise_for_status()
            return r
        except requests.RequestException as e:
            erreur(f"{ERROR}Erreur HTTP ({url}) : {e}{RESET}")
    
    
    # ================= EXTRACTION TOKEN =================
    def extraire_token(url):
        url = url.strip().replace("&", "&")
        try:
            parsed = urlparse(url)
            params = parse_qs(parsed.query)
            otp = params.get("otp", [None])[0]
            playback = params.get("playbackInfo", [None])[0]
            if not otp or not playback:
                raise ValueError("Paramètres manquants")
            return otp, playback
        except Exception as e:
            erreur(f"URL invalide : {e}")
    
    
    # ================= PLAYER =================
    def recuperer_mpd(url):
        headers = {"User-Agent": "Mozilla/5.0", "Referer": url}
        print(f"{INFO}[INFO] Chargement du player...{RESET}")
        html = requete("GET", url, headers=headers).text
        soup = BeautifulSoup(html, "html.parser")
        script = soup.find("script", {"type": "application/json"})
        if not script:
            erreur("Impossible de trouver les métadonnées (token expiré ?)")
        data = json.loads(script.string)
        try:
            return data["dash"]["manifest"]
        except KeyError:
            erreur("MPD introuvable dans la réponse")
    
    
    # ================= PSSH =================
    def extraire_pssh(mpd_url):
        print(f"{INFO}[INFO] Récupération du MPD...{RESET}")
        mpd = requete("GET", mpd_url).text
        match = re.search(r"<cenc:pssh>(.*?)</cenc:pssh>", mpd)
        if not match:
            erreur("PSSH introuvable.")
        return match.group(1)
    
    def encode_license_request(data: bytes) -> str:
        b64 = base64.urlsafe_b64encode(data).decode()
        b64 = b64.replace('-', '+').replace('_', '/')
        return b64
    
    def encode_token(payload: dict) -> str:
        raw = json.dumps(payload).encode()
        b64 = base64.b64encode(raw).decode()
        b64 = b64.replace('/', '_').replace('+', '-')
        return b64
    
    
    # ================= DRM =================
    def obtenir_cles(pssh_b64, otp, playback, url):
        print(f"{INFO}[INFO] Initialisation DRM...{RESET}")
        device = Device.load(WVD_PATH)
        cdm = Cdm.from_device(device)
        session = cdm.open()
        try:
            challenge = cdm.get_license_challenge(session, PSSH(pssh_b64))
            payload = {"playbackInfo": playback, "otp": otp, "href": "https://www.vdocipher.com/", "tech": "wv", "licenseRequest": encode_license_request(challenge)}
            token = {"token": encode_token(payload)}
            headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:150.0) Gecko/20100101 Firefox/150.0", "Origin": "https://player.vdocipher.com", "Referer": "https://player.vdocipher.com/"}
            print(f"{INFO}[INFO] Demande de licence...{RESET}")
            r = requete("POST", "https://license64.vdocipher.com/auth", headers=headers, json=token)
            licence = base64.b64decode(r.json()["license"])
            cdm.parse_license(session, licence)
            print(f"\n{SUCCESS}[SUCCESS] Clés récupérées :\n{RESET}")
            for key in cdm.get_keys(session):
                if key.type != "SIGNING":
                    print(f"{KEY}[KEY] {key.kid.hex()}:{key.key.hex()}{RESET}")
        finally:
            cdm.close(session)
    
    
    # ================= MAIN =================
    def main():
        url = input(f"{DEBUG}Colle l'URL complète du player : {INFO}")
        otp, playback = extraire_token(url)
        print(f"{DEBUG}[DEBUG] OTP:{SUCCESS} {otp}{RESET}")
        print(f"{DEBUG}[DEBUG] PlaybackInfo:{SUCCESS} {playback}{RESET}")
        mpd = recuperer_mpd(url)
        print(f"{INFO}[INFO] MPD :{SUCCESS} {mpd}{RESET}")
        pssh = extraire_pssh(mpd)
        print(f"{INFO}[INFO] PSSH :{SUCCESS} {pssh}{RESET}")
        obtenir_cles(pssh, otp, playback, url)
    
    if __name__ == "__main__":
        main()
    I don't know why I'm getting error 403.
    Image
    [Attachment 92109 - Click to enlarge]
    Quote Quote  
  3. Member
    Join Date
    Dec 2021
    Location
    england
    Search Comp PM
    maybe it need chromecdm l3 if your using it from browser
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!