VideoHelp Forum
+ Reply to Thread
Results 1 to 26 of 26
Thread
  1. https://www.ctv.ca/shows/men-in-black-the-series/the-long-so-long-syndrome-s1e1

    Need CA VPN to view.

    Experimenting with this link, trying to understand process. I got stuck. Was able to obtain keys with l3 guesser extension. dled encrypted files using ytp-dlp. tried to decrypt with keys using mp4 decrypt. mp4 played but looked corrupted.

    What is simplest method? Obtain keys, then download encrypted files, then decrypt? Or is there a better way?

    Please let me know if more info needed.
    Quote Quote  
  2. If mp4 played and it looked corrupted, then most likely your key is wrong.
    Post all the command you used.
    Quote Quote  
  3. Average video editor Sviests's Avatar
    Join Date
    Sep 2018
    Location
    USA,Sweden
    Search Comp PM
    They use different keys for audio and video,so you should have 2 of them popping up. Make sure you use the correct key for each video/audio track.
    (just tested this link,worked fine)
    Quote Quote  
  4. as Sviets says on this video we have multiple keys.

    so:

    1) get key
    Code:
    c98776fd218e995a08ee12e5506f9f90:21efd0916ba347459c2e49990baee54d
    e14526eb374792d803d8ee914d074b94:89d0d7a9405b6da5ba0202c136dc2974
    c98776fd218e995a08ee12e5506f9f90:63d0e8e1f8ee22fecb9a84ed24252678
    e14526eb374792d803d8ee914d074b94:f63f155b79f4cae91b21d2c933051486
    2) download
    Code:
    yt-dlp --allow-u https://capi.9c9media.com/destinations/ctvthrowback_hub/platforms/desktop/bond/contents/1610050/contentpackages/2592349/manifest.mpd
    3) decrypt
    Code:
    mp4decrypt --key1 <id>:<k> --key2 <id>:<k> --key3 <id>:<k> --key4 <id>:<k> <input> <output>
    4) merge audio&video with ffmpeg
    Code:
    ffmpeg -i video.mp4 -i audio.m4a -c copy muxed.mp4
    Quote Quote  
  5. Originally Posted by lomero View Post
    3) decrypt
    Code:
    mp4decrypt --key1 <id>:<k> --key2 <id>:<k> --key3 <id>:<k> --key4 <id>:<k> <input> <output>
    I have the keys
    [{"key":"2586210ff9fe553585fd97b58744e8d3:9a6823219 a01069c3d351465c5c98076"},{"key":"4aebae8308c85a2c af51bfb29a247a33:1ff3c2f9f81d089dd630f3b993fbff10" },{"key":"51fe361f95e657918dc0ef6087ae637f:4d220eb 1e9ab9abb1bb36257903e5bd2"}]

    KID="a923ac15-9c54-43c2-b2ad-eda228bc2f9a"

    Trying to decrypt

    Code:
    mp4decrypt --key1 2586210ff9fe553585fd97b58744e8d3:9a6823219a01069c3d351465c5c98076  --key2 4aebae8308c85a2caf51bfb29a247a33:1ff3c2f9f81d089dd630f3b993fbff10 --key3 51fe361f95e657918dc0ef6087ae637f:4d220eb1e9ab9abb1bb36257903e5bd2  video-v1.mp4 my_decrypted_file.mp4
    but I get an error
    Code:
    D:\video>:>mp4decrypt --key1 2586210ff9fe553585fd97b58744e8d3:9a6823219a01069c3d351465c5c98076  --key2 4aebae8308c85a2caf51bfb29a247a33:1ff3c2f9f81d089dd630f3b993fbff10 --key3 51fe361f95e657918dc0ef6087ae637f:4d220eb1e9ab9abb1bb36257903e5bd2  video-v1.mp4 my_decrypted_file.mp4
    ERROR: unexpected argument (--key2)
    Last edited by mister_ nex; 4th Dec 2021 at 07:25.
    Quote Quote  
  6. Correct syntax:

    mp4decrypt --key 2586210ff9fe553585fd97b58744e8d3:9a6823219a01069c3 d351465c5c98076 --key 4aebae8308c85a2caf51bfb29a247a33:1ff3c2f9f81d089dd 630f3b993fbff10 --key 51fe361f95e657918dc0ef6087ae637f:4d220eb1e9ab9abb1 bb36257903e5bd2 video-v1.mp4 my_decrypted_file.mp4
    Quote Quote  
  7. yea, my post#4 is only to an example
    when you decrypt, don't write number after --key, as pedrothelion says.
    Quote Quote  
  8. Thanks!
    syntax ok, but dont decrypt.
    I will try with another site
    Last edited by mister_ nex; 4th Dec 2021 at 08:16.
    Quote Quote  
  9. write here your decrypt command.
    or bad syntax or bad key.
    Quote Quote  
  10. Works fine everything,decrypted all files

    (the keys in this example are random)

    Code:
    mp4decrypt --key 1eccbb506ef45ffd9df4f19e7fa41043:2f3d558402056f588f0542e789c07a3d  --key 2bf55dfccb93568ba0b26ac745ad78cc:147fe2333087487524c909e4bae2e70c --key ec421b95709e583a88e9fe4fff3d3da8:382c3435884836a5a4eb48c9b3894448  encrypt.mp4 decrypted.mp4
    Quote Quote  
  11. Thanks, lomero, for the tip above using yt-dlp to just get the file!

    Before I learned that trick with yt-dlp, I was using N_m3u8_DL. Basically the same thing but needs you do BaseURL as well as it oddly just errors out with the MPD unlike yt-dlp.

    I will admit, if you are going to get a Series with yt-dlp, I would do -o SHOW-SXXEXX at the end of yt-dlp or something similar. Otherwise, you can go nuts with tons of files named Manifest-XXXX.
    Last edited by RedPenguin; 4th Dec 2021 at 18:29.
    Quote Quote  
  12. How do you get the PSSH for CTV.ca? It's not in the MPD. The MPD doesn't even have the KID. I tried using mp4dump with the init.mp4 file and I couldn't get that to work either. Can someone tell me how to get the proper PSSH? Thanks
    Quote Quote  
  13. Originally Posted by achilles View Post
    I tried using mp4dump with the init.mp4 file and I couldn't get that to work either.
    Why?
    Works fine.
    Example
    https://www.ctv.ca/shows/men-in-black-the-series/the-long-so-long-syndrome-s1e1
    Code:
    mp4dump.exe init.mp4
    [ftyp] size=8+20
      major_brand = isom
      minor_version = 0
      compatible_brand = isom
      compatible_brand = iso5
      compatible_brand = iso6
    [moov] size=8+876
      [mvhd] size=12+96
        timescale = 30000
        duration = 0
        duration(ms) = 0
      [trak] size=8+570
        [tkhd] size=12+80, flags=7
          enabled = 1
          id = 1
          duration = 0
          width = 1280.000000
          height = 720.000000
        [mdia] size=8+470
          [mdhd] size=12+20
            timescale = 30000
            duration = 0
            duration(ms) = 0
            language = und
          [hdlr] size=12+25
            handler_type = vide
            handler_name =
          [minf] size=8+393
            [vmhd] size=12+8, flags=1
              graphics_mode = 0
              op_color = 0000,0000,0000
            [dinf] size=8+28
              [dref] size=12+16
                [url ] size=12+0, flags=1
                  location = [local to file]
            [stbl] size=8+329
              [stsd] size=12+249
                entry_count = 1
                [encv] size=8+237
                  data_reference_index = 1
                  width = 1280
                  height = 720
                  compressor =
                  [avcC] size=8+51
                    Configuration Version = 1
                    Profile = Main
                    Profile Compatibility = 40
                    Level = 31
                    NALU Length Size = 4
                    Sequence Parameter = [27 4d 40 1f b9 18 0a 00 b7 60 22 00 00 07 d2 00 01 d4 c1 c0 40 00 63 2e 80 00 31 97 5d ef 70 1f 08 84 53 80]
                    Picture Parameter = [28 fe bc 80]
                  [btrt] size=8+12
                  [sinf] size=8+72
                    [frma] size=8+4
                      original_format = avc1
                    [schm] size=12+8
                      scheme_type = cenc
                      scheme_version = 65536
                    [schi] size=8+32
                      [tenc] size=12+20
                        default_isProtected = 1
                        default_Per_Sample_IV_Size = 8
                        default_KID = [c9 87 76 fd 21 8e 99 5a 08 ee 12 e5 50 6f 9f 90]
              [stts] size=12+4
                entry_count = 0
              [stsc] size=12+4
                entry_count = 0
              [stsz] size=12+8
                sample_size = 0
                sample_count = 0
              [stco] size=12+4
                entry_count = 0
      [mvex] size=8+32
        [trex] size=12+20
          track id = 1
          default sample description index = 1
          default sample duration = 0
          default sample size = 0
          default sample flags = 0
      [pssh] size=12+138
        system_id = [ed ef 8b a9 79 d6 4a ce a3 c8 27 dc d5 1d 21 ed]
        data_size = 118
    So KID is
    Code:
    c98776fd218e995a08ee12e5506f9f90
    Then we use this python script to get pssh from kid
    Code:
    import base64
    
    def get_pssh(keyId):
        array_of_bytes = bytearray( b'\x00\x00\x002pssh\x00\x00\x00\x00')
        array_of_bytes.extend(bytes.fromhex("edef8ba979d64acea3c827dcd51d21ed"))
        array_of_bytes.extend(b'\x00\x00\x00\x12\x12\x10')
        array_of_bytes.extend(bytes.fromhex( keyId.replace("-", "")))
        return base64.b64encode(bytes.fromhex(array_of_bytes.hex()))
    
    kid = input("Please input KID in hex string: ")
    kid = kid.replace('-', '')
    assert len(kid) == 32 and not isinstance(kid, bytes), "wrong KID length"
    print("PSSH {}".format(get_pssh(kid).decode('utf-8')))
    Which gives us
    Code:
    AAAAMnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABISEMmHdv0hjplaCO4S5VBvn5A=
    which should be the PSSH.

    You are gonna have more trouble with sending the license request, though.
    Quote Quote  
  14. Thank you very much for the code snippet. That makes life much easier rather than using a website to generate the PSSH from the KID.

    My mistake had been trying to generate the PSSH from the [pssh] part of the mp4dump rather than just from the KID. (I swear, on another file I tried, there was more data there rather than just the widevine ID).

    When I try the PSSH on the getwvkeys site, I get an unspecified error. I'm pretty sure the license url is:
    Code:
    https://license.9c9media.ca/widevine
    I'll keep trying. Maybe I'm doing something wrong with headers.
    Quote Quote  
  15. Originally Posted by achilles View Post
    Thank you very much for the code snippet. That makes life much easier rather than using a website to generate the PSSH from the KID.

    My mistake had been trying to generate the PSSH from the [pssh] part of the mp4dump rather than just from the KID. (I swear, on another file I tried, there was more data there rather than just the widevine ID).

    When I try the PSSH on the getwvkeys site, I get an unspecified error. I'm pretty sure the license url is:
    Code:
    https://license.9c9media.ca/widevine
    I'll keep trying. Maybe I'm doing something wrong with headers.
    Just get EME-Logger for Grease/Tamper Monkey and it will give you the PSSH always in Console of Web Tools.

    Also CTV.ca only has 2 keys each (first one for video and second for audio). If you have the headers wrong, the license server oddly throws you 3 random keys. Once you copy the correct headers from Web Tools, you should get only a 2 key response.

    EDIT: Check your PSSH, because even without changing headers on getwvkeys (I've been using WKS mostly), I do get the correct keys for a PSSH from CTV.ca.
    Quote Quote  
  16. Thanks for that tip. I will try that as well to make sure I've got everything right. I'll keep trying stuff and see if I can figure this out. Although it's good to know that other people have gotten this to work so there's a place I can go for help if I'm totally stuck. Thanks!

    UPDATE: Finally got it working. Thanks everyone!
    Last edited by achilles; 7th Dec 2021 at 08:34.
    Quote Quote  
  17. Originally Posted by [ss]vegeta View Post
    Originally Posted by achilles View Post
    I tried using mp4dump with the init.mp4 file and I couldn't get that to work either.
    Why?
    Works fine.
    Example
    https://www.ctv.ca/shows/men-in-black-the-series/the-long-so-long-syndrome-s1e1
    Code:
    mp4dump.exe init.mp4
    [ftyp] size=8+20
      major_brand = isom
      minor_version = 0
      compatible_brand = isom
      compatible_brand = iso5
      compatible_brand = iso6
    [moov] size=8+876
      [mvhd] size=12+96
        timescale = 30000
        duration = 0
        duration(ms) = 0
      [trak] size=8+570
        [tkhd] size=12+80, flags=7
          enabled = 1
          id = 1
          duration = 0
          width = 1280.000000
          height = 720.000000
        [mdia] size=8+470
          [mdhd] size=12+20
            timescale = 30000
            duration = 0
            duration(ms) = 0
            language = und
          [hdlr] size=12+25
            handler_type = vide
            handler_name =
          [minf] size=8+393
            [vmhd] size=12+8, flags=1
              graphics_mode = 0
              op_color = 0000,0000,0000
            [dinf] size=8+28
              [dref] size=12+16
                [url ] size=12+0, flags=1
                  location = [local to file]
            [stbl] size=8+329
              [stsd] size=12+249
                entry_count = 1
                [encv] size=8+237
                  data_reference_index = 1
                  width = 1280
                  height = 720
                  compressor =
                  [avcC] size=8+51
                    Configuration Version = 1
                    Profile = Main
                    Profile Compatibility = 40
                    Level = 31
                    NALU Length Size = 4
                    Sequence Parameter = [27 4d 40 1f b9 18 0a 00 b7 60 22 00 00 07 d2 00 01 d4 c1 c0 40 00 63 2e 80 00 31 97 5d ef 70 1f 08 84 53 80]
                    Picture Parameter = [28 fe bc 80]
                  [btrt] size=8+12
                  [sinf] size=8+72
                    [frma] size=8+4
                      original_format = avc1
                    [schm] size=12+8
                      scheme_type = cenc
                      scheme_version = 65536
                    [schi] size=8+32
                      [tenc] size=12+20
                        default_isProtected = 1
                        default_Per_Sample_IV_Size = 8
                        default_KID = [c9 87 76 fd 21 8e 99 5a 08 ee 12 e5 50 6f 9f 90]
              [stts] size=12+4
                entry_count = 0
              [stsc] size=12+4
                entry_count = 0
              [stsz] size=12+8
                sample_size = 0
                sample_count = 0
              [stco] size=12+4
                entry_count = 0
      [mvex] size=8+32
        [trex] size=12+20
          track id = 1
          default sample description index = 1
          default sample duration = 0
          default sample size = 0
          default sample flags = 0
      [pssh] size=12+138
        system_id = [ed ef 8b a9 79 d6 4a ce a3 c8 27 dc d5 1d 21 ed]
        data_size = 118
    So KID is
    Code:
    c98776fd218e995a08ee12e5506f9f90
    Then we use this python script to get pssh from kid
    Code:
    import base64
    
    def get_pssh(keyId):
        array_of_bytes = bytearray( b'\x00\x00\x002pssh\x00\x00\x00\x00')
        array_of_bytes.extend(bytes.fromhex("edef8ba979d64acea3c827dcd51d21ed"))
        array_of_bytes.extend(b'\x00\x00\x00\x12\x12\x10')
        array_of_bytes.extend(bytes.fromhex( keyId.replace("-", "")))
        return base64.b64encode(bytes.fromhex(array_of_bytes.hex()))
    
    kid = input("Please input KID in hex string: ")
    kid = kid.replace('-', '')
    assert len(kid) == 32 and not isinstance(kid, bytes), "wrong KID length"
    print("PSSH {}".format(get_pssh(kid).decode('utf-8')))
    Which gives us
    Code:
    AAAAMnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABISEMmHdv0hjplaCO4S5VBvn5A=
    which should be the PSSH.

    You are gonna have more trouble with sending the license request, though.

    Excellent explanation and method. Please, can you share python script
    Quote Quote  
  18. Originally Posted by lOiShful View Post
    Please, can you share python script
    What Python script?
    Just copy that code in Notepad, save it as kid.py, make sure you have Python installed and just open cmd in the folder where kid.py is and type kid.py and press enter.

    Anyways, you are better off using this EME thing, because sometimes the Python script I posted won't be of use. It requires for you to download the init and sometimes that's not possible.
    Quote Quote  
  19. Originally Posted by [ss]vegeta View Post
    Originally Posted by lOiShful View Post
    Please, can you share python script
    What Python script?
    Just copy that code in Notepad, save it as kid.py, make sure you have Python installed and just open cmd in the folder where kid.py is and type kid.py and press enter.

    Anyways, you are better off using this EME thing, because sometimes the Python script I posted won't be of use. It requires for you to download the init and sometimes that's not possible.

    Regarding generating the pssh, I also prefer to try various ways manually. Indeed, EME Logger works very well.


    On the other hand, when I run kid.py, as shown in the screenshot, I get the following message:

    Image
    [Attachment 62250 - Click to enlarge]



    Thank you for your help!
    Quote Quote  
  20. Originally Posted by lOiShful View Post
    On the other hand, when I run kid.py, as shown in the screenshot, I get the following message:
    You added something that you shouldn't have. Try copying again.
    Maybe you missed a bracket of the last 3?
    Quote Quote  
  21. Originally Posted by [ss]vegeta View Post
    Originally Posted by lOiShful View Post
    On the other hand, when I run kid.py, as shown in the screenshot, I get the following message:
    You added something that you shouldn't have. Try copying again.
    Maybe you missed a bracket of the last 3?

    Yes, indeed, I copied the code wrong: the last parenthesis was missing. Again, I appreciate the help. Greetings!
    Quote Quote  
  22. ....................
    Last edited by chronics; 1st Feb 2022 at 16:35.
    Quote Quote  
  23. Originally Posted by [ss]vegeta View Post
    https://www.ctv.ca/shows/men-in-black-the-series/the-long-so-long-syndrome-s1e1
    Code:
    mp4dump.exe init.mp4
    [ftyp] size=8+20
      major_brand = isom
      minor_version = 0
      compatible_brand = isom
      compatible_brand = iso5
      compatible_brand = iso6
    [moov] size=8+876
      [mvhd] size=12+96
        timescale = 30000
        duration = 0
        duration(ms) = 0
      [trak] size=8+570
        [tkhd] size=12+80, flags=7
          enabled = 1
          id = 1
          duration = 0
          width = 1280.000000
          height = 720.000000
        [mdia] size=8+470
          [mdhd] size=12+20
            timescale = 30000
            duration = 0
            duration(ms) = 0
            language = und
          [hdlr] size=12+25
            handler_type = vide
            handler_name =
          [minf] size=8+393
            [vmhd] size=12+8, flags=1
              graphics_mode = 0
              op_color = 0000,0000,0000
            [dinf] size=8+28
              [dref] size=12+16
                [url ] size=12+0, flags=1
                  location = [local to file]
            [stbl] size=8+329
              [stsd] size=12+249
                entry_count = 1
                [encv] size=8+237
                  data_reference_index = 1
                  width = 1280
                  height = 720
                  compressor =
                  [avcC] size=8+51
                    Configuration Version = 1
                    Profile = Main
                    Profile Compatibility = 40
                    Level = 31
                    NALU Length Size = 4
                    Sequence Parameter = [27 4d 40 1f b9 18 0a 00 b7 60 22 00 00 07 d2 00 01 d4 c1 c0 40 00 63 2e 80 00 31 97 5d ef 70 1f 08 84 53 80]
                    Picture Parameter = [28 fe bc 80]
                  [btrt] size=8+12
                  [sinf] size=8+72
                    [frma] size=8+4
                      original_format = avc1
                    [schm] size=12+8
                      scheme_type = cenc
                      scheme_version = 65536
                    [schi] size=8+32
                      [tenc] size=12+20
                        default_isProtected = 1
                        default_Per_Sample_IV_Size = 8
                        default_KID = [c9 87 76 fd 21 8e 99 5a 08 ee 12 e5 50 6f 9f 90]
              [stts] size=12+4
                entry_count = 0
              [stsc] size=12+4
                entry_count = 0
              [stsz] size=12+8
                sample_size = 0
                sample_count = 0
              [stco] size=12+4
                entry_count = 0
      [mvex] size=8+32
        [trex] size=12+20
          track id = 1
          default sample description index = 1
          default sample duration = 0
          default sample size = 0
          default sample flags = 0
      [pssh] size=12+138
        system_id = [ed ef 8b a9 79 d6 4a ce a3 c8 27 dc d5 1d 21 ed]
        data_size = 118
    So KID is
    Code:
    c98776fd218e995a08ee12e5506f9f90
    Then we use this python script to get pssh from kid
    Code:
    import base64
    
    def get_pssh(keyId):
        array_of_bytes = bytearray( b'\x00\x00\x002pssh\x00\x00\x00\x00')
        array_of_bytes.extend(bytes.fromhex("edef8ba979d64acea3c827dcd51d21ed"))
        array_of_bytes.extend(b'\x00\x00\x00\x12\x12\x10')
        array_of_bytes.extend(bytes.fromhex( keyId.replace("-", "")))
        return base64.b64encode(bytes.fromhex(array_of_bytes.hex()))
    
    kid = input("Please input KID in hex string: ")
    kid = kid.replace('-', '')
    assert len(kid) == 32 and not isinstance(kid, bytes), "wrong KID length"
    print("PSSH {}".format(get_pssh(kid).decode('utf-8')))
    Which gives us
    Code:
    AAAAMnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABISEMmHdv0hjplaCO4S5VBvn5A=
    which should be the PSSH.

    You are gonna have more trouble with sending the license request, though.


    did ctv change their method? it errors for me


    C:\WKS-KEYS>l3.py

    PSSH: AAAAMnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABISEMmHdv 0hjplaCO4S5VBvn5A=
    License URL: https://license.9c9media.ca/widevine
    Traceback (most recent call last):
    File "C:\WKS-KEYS\l3.py", line 25, in <module>
    correct, keys = WV_Function(pssh, lic_url)
    File "C:\WKS-KEYS\l3.py", line 21, in WV_Function
    wvdecrypt.update_license(license_b64)
    File "C:\WKS-KEYS\pywidevine\L3\decrypt\wvdecryptcustom.py", line 58, in update_license
    self.cdm.provide_license(self.session, license_b64)
    File "C:\WKS-KEYS\pywidevine\L3\cdm\cdm.py", line 275, in provide_license
    session.session_key = oaep_cipher.decrypt(license.SessionKey)
    File "C:\Users\User\AppData\Local\Programs\Python\Pytho n39\lib\site-packages\Cryptodome\Cipher\PKC
    S1_OAEP.py", line 167, in decrypt
    raise ValueError("Ciphertext with incorrect length.")
    ValueError: Ciphertext with incorrect length.
    Quote Quote  
  24. Originally Posted by ricky70 View Post
    did ctv change their method? it errors for me
    Post the link you are trying to get keys for.
    Quote Quote  
  25. Originally Posted by [ss]vegeta View Post
    Post the link you are trying to get keys for.
    sure, its the same link as your test

    https://www.ctv.ca/shows/men-in-black-the-series/the-long-so-long-syndrome-s1e1
    Quote Quote  
  26. I just checked it myself.

    Code:
    PSSH: AAAAlnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAHYIARIQ4UUm6zdHktgD2O6RTQdLlBoJYmVsbG1lZGlhIlVwbGF5bGlzdC8yNTkyMzQ5LzMxMjI1MjExL2Rhc2gvMjAxMzAwMDEvMzA2ZjM2NTRjYzUyNTYzNS9pbmRleC81YzcxOWUxYi9ub25lL25vbmUvZHJt
    --key c98776fd218e995a08ee12e5506f9f90:63d0e8e1f8ee22fecb9a84ed24252678
    --key e14526eb374792d803d8ee914d074b94:f63f155b79f4cae91b21d2c933051486
    For some reason EME-Logger gave me a different PSSH than [ss]vegeta posted as that one does give me CipherText with incorrect length. But the method is definitely still working to get keys.
    Quote Quote  



Similar Threads

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