把 QMC2 加密的音频文件(.mgg / .mflac)解密还原成可直接播放的 OGG / FLAC,按需再转 MP3 / WAV。
Decrypt QMC2-encrypted audio files (
.mgg/.mflac) back to plain Ogg Vorbis / FLAC, optionally re-encode to MP3. Pure Python, no external crypto library: TC-TEA + QMC2 Map/RC4 stream cipher.
.mgg 不是一种音频编码,而是 QMC2 加密的 Ogg Vorbis;.mflac 是 QMC2 加密的 FLAC。所以「转换」的本质是解密 + 换扩展名,不需要重新编码,原始音频流本身是完好的。
- 自动识别三种文件尾部:QTag(ekey 内嵌)、V1(原始 key 内嵌)、musicex(需外部 ekey)
- 内嵌密钥 → TC-TEA(16 轮,EncV1 / EncV2 两代格式)→ 128~256 字节密钥
- 短密钥走 Map 流密码(numpy 向量化,12 MB 约 2 秒;无 numpy 自动退回纯 Python)
- 长密钥走 RC4 变体
- 解密后自校验:魔数、Ogg 页序列连续性、结尾对齐;
--crc可逐页校验 - 一条命令顺带转 320 kbps MP3(自动寻找 ffmpeg,含
imageio-ffmpeg兜底) - 零第三方依赖(除可选的 numpy / imageio-ffmpeg)
# 解密:song.mgg -> song.ogg
python scripts/qmc_decrypt.py "song [qmms2].mgg"
# 指定输出名
python scripts/qmc_decrypt.py "song.mgg" -o "Dennis Kuo - Ever Eternity.ogg"
# 只看文件结构,不解密
python scripts/qmc_decrypt.py "song.mgg" --info
# 解密 + 逐页 CRC 校验(怀疑文件损坏时用)
python scripts/qmc_decrypt.py "song.mgg" --crc
# 解密 + 直接转 320k MP3
python scripts/qmc_decrypt.py "song.mgg" --to-mp3
# musicex 格式:ekey 不在文件里,需要自己提供
python scripts/qmc_decrypt.py "song.mgg" --ekey "<base64 ekey>"典型输出:
[file] Dennis Kuo - Ever Eternity [qmms2].mgg size=12146287 footer=qtag audio_bytes=12145905
[footer] song_id=8557419 ekey_len=364
[key] derived=256 bytes -> MAP cipher
[out] wrote Dennis Kuo - Ever Eternity.ogg (12145905 bytes, head=b'OggS')
[verify] ogg pages=2759 serials=1 stream_end_exact=True
| 扩展名 | 内容 | 输出 | 状态 |
|---|---|---|---|
.mgg .mgg0 .mgg1 .mggl |
QMC2 + Ogg Vorbis | .ogg |
✅ 实测通过 |
.mflac .mflac0 .mflach |
QMC2 + FLAC | .flac |
✅ 算法一致 |
.qmc0 .qmc2 .qmc3 .qmcflac .qmcogg |
早期 QMC1(固定异或表,无 ekey) | — | ❌ 不在范围内 |
QMC1 是另一套算法,用本工具的流程去解只会得到噪声,请改用 unlock-music 等带 QMC1 实现的工具。
文件尾部 → 提取 ekey → TC-TEA 解密 → 派生 256B 密钥 → Map/RC4 流解密 → 原始音频流
三种尾部布局:
QTag: [加密音频][ekey,song_id,ver][u32 BIG-ENDIAN 长度 L]["QTag"]
V1: [加密音频][原始 key 字节 K][u32 LITTLE-ENDIAN K]
musicex: [加密音频][176 B 元数据][u32 footer_size=192][u32 version=1]["musicex\0"]
密钥派生与密码细节见 references/qmc2-algorithm.md:TEA 的 PadLen|Padding|Salt|Body|Zero(7) 块链规则、SIMPLE 常量、Map 掩码公式、RC4 分段规则,以及一个完整的回归样例(输入/输出大小、页数、SHA-256)。
Map 掩码的下标是 offset if offset <= 0x7FFF else offset % 0x7FFF。若把 0x7FFF 那一个字节也写成 offset % 0x7FFF,它会算成 0 —— 只错 1 个字节,症状却是「全文件仅 1 页 Ogg CRC 不匹配、其余 2758 页全对」。看到这个症状先查取模边界,不要去「修复」 CRC,那只会把 bug 藏起来。
python tests/test_qmc.py覆盖:TC-TEA 官方测试向量、SIMPLE 常量、三种尾部解析、Map 的 0x7FFF 边界与 numpy/纯 Python 一致性、RC4 往返。全部离线,不需要样本文件。
.
├── SKILL.md # agent skill 入口(触发条件 + 流程 + 排错)
├── scripts/qmc_decrypt.py # 全部实现,也可当独立 CLI 用
├── references/qmc2-algorithm.md# 算法细节与回归样例
└── tests/test_qmc.py # 自测
SKILL.md 的存在意味着这个仓库同时是一个 DeepSeek Harness 风格的 agent skill:把目录放进 ~/.dsh/skills/ 或项目的 .dsh/skills/,agent 遇到 .mgg 文件时会自动加载并按流程处理。
本项目仅用于处理你本人合法获取的音频文件(自己购买或下载的音乐),目的是让这些文件能在自己的设备上正常播放与剪辑。
- 请勿用于绕过付费、传播他人作品或任何侵犯版权的用途。
- 解密后的音频仍受原始版权约束,不因格式转换而改变。
- 使用者需自行承担合规责任;作者不对任何滥用行为负责。
- ownlight6/qmc-decoder —— QMC1/QMC2 的 Rust 实现与尾部格式分析,本项目的 Python 移植蓝本
tc_teacrate —— TC-TEA 的填充与块链规则定义,含官方测试向量- unlock-music —— 同类工具的完整参考实现