56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
import base64
|
|
import pathlib
|
|
|
|
from Crypto.Cipher import AES
|
|
from Crypto.Util import Counter
|
|
|
|
|
|
def decrypt_security_token(security_token: str) -> (str, str):
|
|
"""
|
|
Decrypts security token into key and nonce pair
|
|
|
|
security_token should match the securityToken value from the web response
|
|
"""
|
|
|
|
# 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)
|