From ca8c8aa490ca5da34a7d0174b2112a4654018973 Mon Sep 17 00:00:00 2001 From: ypshidifu Date: Thu, 17 Sep 2026 21:32:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=20KGM=E8=A7=A3=E5=AF=86?= =?UTF-8?q?=E5=B9=B6=E8=A1=8C=E5=8C=96=EF=BC=8C=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E5=A4=84=E7=90=86block=EF=BC=8C=E6=8F=90=E5=8D=87=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E5=8D=A1=E9=A1=BF=E6=97=B6=E8=BD=AC=E7=A0=81?= =?UTF-8?q?=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vipsong.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/vipsong.py b/vipsong.py index e74e374..2659135 100644 --- a/vipsong.py +++ b/vipsong.py @@ -9,6 +9,7 @@ from mutagen.flac import FLAC from mutagen.oggvorbis import OggVorbis from mutagen.id3 import ID3, TIT2, TPE1, TALB, APIC from pydub import AudioSegment +from concurrent.futures import ThreadPoolExecutor NCM_MAGIC = b"CTENFDAM" CORE_KEY = b"hzHRAmso5kInbaxW" @@ -262,16 +263,26 @@ class KgmDecoder: pub_len = len(self.pub_key) out = bytearray(len(audio)) block_count = (len(audio) + BLOCK - 1) // BLOCK - for block_idx in range(block_count): - if block_idx >= pub_len: - raise ValueError("Key file mismatch") + if block_count > pub_len: + raise ValueError("Key file mismatch") + # Pre-compute all 17 phase tables; workers only read from cache + for phase in range(17): + self._phase_tables(phase, own_key, self.pub_key) + # Parallel block decryption: each block is independent + def _decrypt_block(block_idx): phase = block_idx % 17 tables = self._phase_tables(phase, own_key, self.pub_key) pub_value = self.pub_key[block_idx] start = block_idx * BLOCK end = min(start + BLOCK, len(audio)) - for col, offset in enumerate(range(start, end)): - out[offset] = tables[col][pub_value][audio[offset]] + blk = bytearray(end - start) + for col in range(end - start): + blk[col] = tables[col][pub_value][audio[start + col]] + return start, bytes(blk) + max_workers = min(16, max(1, block_count)) + with ThreadPoolExecutor(max_workers=max_workers) as executor: + for start, blk in executor.map(_decrypt_block, range(block_count)): + out[start:start + len(blk)] = blk payload = bytes(out) container = _sniff_container(payload[:64]) return payload, container, {}, None