summaryrefslogtreecommitdiff
path: root/tidal_dl_ng/helper/decryption.py
blob: 2f38fc5236d22042b5920ba15559e8a675c30ae7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import base64
import pathlib

from Crypto.Cipher import AES
from Crypto.Util import Counter


def decrypt_security_token(security_token: str) -> (str, str):
    """
    The `decrypt_security_token` function decrypts a security token into a key and nonce pair using AES
    encryption.

    Args:
      security_token (str): The `security_token` parameter in the `decrypt_security_token` function is a
    string that represents an encrypted security token. This function decrypts the security token into a
    key and nonce pair using AES encryption. security_token should match the securityToken value from the web response.

    Returns:
      The `decrypt_security_token` function returns a tuple containing the key and nonce extracted from
    the decrypted security token.
    """

    # Do not change this
    master_key = "UIlTTEMmmLfGowo/UC60x2H45W6MdGgTRfo/umg4754="

    # Decode the base64 strings to ascii strings
    master_key = base64.b64decode(master_key)
    security_token = base64.b64decode(security_token)

    # Get the IV from the first 16 bytes of the securityToken
    iv = security_token[:16]
    encrypted_st = security_token[16:]

    # Initialize decryptor
    decryptor = AES.new(master_key, AES.MODE_CBC, iv)

    # Decrypt the security token
    decrypted_st = decryptor.decrypt(encrypted_st)

    # Get the audio stream decryption key and nonce from the decrypted security token
    key = decrypted_st[:16]
    nonce = decrypted_st[16:24]

    return key, nonce


def decrypt_file(path_file_encrypted: pathlib.Path, path_file_destination: pathlib.Path, key: str, nonce: str) -> None:
    """
    Decrypts an encrypted MQA file given the file, key and nonce.
    TODO: Is it really only necessary for MQA of for all other formats, too?
    """

    # Initialize counter and file decryptor
    counter = Counter.new(64, prefix=nonce, initial_value=0)
    decryptor = AES.new(key, AES.MODE_CTR, counter=counter)

    # Open and decrypt
    with path_file_encrypted.open("rb") as f_src:
        audio_decrypted = decryptor.decrypt(f_src.read())

        # Replace with decrypted file
        with path_file_destination.open("wb") as f_dst:
            f_dst.write(audio_decrypted)