73 lines
1.9 KiB
Python
73 lines
1.9 KiB
Python
from Crypto.Cipher import AES
|
|
from Crypto.Util import Counter
|
|
from librespot.audio.storage import ChannelManager
|
|
from librespot.audio.decrypt.AudioDecrypt import AudioDecrypt
|
|
import time
|
|
|
|
|
|
class AesAudioDecrypt(AudioDecrypt):
|
|
audio_aes_iv = bytes(
|
|
[
|
|
0x72,
|
|
0xE0,
|
|
0x67,
|
|
0xFB,
|
|
0xDD,
|
|
0xCB,
|
|
0xCF,
|
|
0x77,
|
|
0xEB,
|
|
0xE8,
|
|
0xBC,
|
|
0x64,
|
|
0x3F,
|
|
0x63,
|
|
0x0D,
|
|
0x93,
|
|
]
|
|
)
|
|
iv_int = int.from_bytes(audio_aes_iv, "big")
|
|
iv_diff = 0x100
|
|
cipher = None
|
|
decrypt_count = 0
|
|
decrypt_total_time = 0
|
|
key: bytes = None
|
|
|
|
def __init__(self, key: bytes):
|
|
self.key = key
|
|
|
|
def decrypt_chunk(self, chunk_index: int, buffer: bytes):
|
|
new_buffer = b""
|
|
iv = self.iv_int + int(ChannelManager.CHUNK_SIZE * chunk_index / 16)
|
|
start = time.time_ns()
|
|
for i in range(0, len(buffer), 4096):
|
|
cipher = AES.new(
|
|
key=self.key,
|
|
mode=AES.MODE_CTR,
|
|
counter=Counter.new(128, initial_value=iv),
|
|
)
|
|
|
|
count = min(4096, len(buffer) - i)
|
|
decrypted_buffer = cipher.decrypt(buffer[i : i + count])
|
|
new_buffer += decrypted_buffer
|
|
if count != len(decrypted_buffer):
|
|
raise RuntimeError(
|
|
"Couldn't process all data, actual: {}, expected: {}".format(
|
|
len(decrypted_buffer), count
|
|
)
|
|
)
|
|
|
|
iv += self.iv_diff
|
|
|
|
self.decrypt_total_time += time.time_ns()
|
|
self.decrypt_count += 1
|
|
|
|
return new_buffer
|
|
|
|
def decrypt_time_ms(self):
|
|
return (
|
|
0
|
|
if self.decrypt_count == 0
|
|
else int((self.decrypt_total_time / self.decrypt_count) / 1000000)
|
|
)
|