-
Notifications
You must be signed in to change notification settings - Fork 1
Decryption
ChouChiu edited this page Sep 23, 2026
·
3 revisions
库提供 QQ 音乐 QRC 与酷狗音乐 KRC 两种专有加密格式的解密实现。顶层便捷函数 decrypt_qrc() 与 decrypt_krc() 失败时返回 None;如需获取具体错误原因,可使用实现了 LyricsDecrypter 的 QrcDecrypter 与 KrcDecrypter。
QRC 密文为十六进制编码字符串。解密流水线:
- 过滤空白字符并进行十六进制解码。
- Triple DES(3DES-EDE,固定 24 字节密钥)按 8 字节分组解密。
- zlib 解压缩。
- UTF-8 文本解码。
use lyrics_helper::{decrypt_qrc, parse, LyricsRawTypes};
fn main() {
let encrypted = "9FD341D70ACF96D59FB0C7DBB4D6DC3597BDB2000DB276840C98E56C039C7200698E953B\
BA404B8F7B04CF1342633627F64E04CEF5B16748696B9A64B3987B174943C1CE7EFB04A0\
725C8833D4ED3DA19E2B2B2EAE76F5365BE4571E7EA46C44";
if let Some(decrypted) = decrypt_qrc(encrypted) {
println!("解密后的 QRC 文本:\n{decrypted}");
let data = parse(&decrypted, LyricsRawTypes::Qrc).expect("解析失败");
println!("解析得到 {} 行歌词", data.lines.as_ref().map_or(0, Vec::len));
}
}KRC 密文为 Base64 编码的二进制流。解密流水线:
- Base64 解码。
- 跳过开头的 4 字节魔数头(
krc1)。 - 使用固定 16 字节密钥逐字节循环异或(XOR)。
- zlib 解压缩。
- 去除正文开头的 UTF-8 BOM(
0xEF, 0xBB, 0xBF,若存在)。 - UTF-8 文本解码。
Note
酷狗以 charset=utf8 下发 KRC,解压后的正文普遍带有 UTF-8 BOM。上游 C# 实现采用 Encoding.UTF8.GetString(...)[1..] 方式解码后再丢弃首个字符;本库仅在检测到 BOM 字节序列时才予以剥离,既避免了无 BOM 时吞掉正文首字符的问题,也防止按字节截断导致 UTF-8 序列破损。
use lyrics_helper::{decrypt_krc, parse, LyricsRawTypes};
fn main() {
// 带有 krc1 魔数头与 UTF-8 BOM 的 KRC 文件 Base64
let krc_content = "a3JjMTidGsglTQAO96N6R6CsQj70xu/m37M169y3v7RPU+Do3QAL+VO6caa00kJo1dGLHMwLQ\
P1Sv7SlsM90FOeOblfHU2Y=";
if let Some(decrypted) = decrypt_krc(krc_content) {
let data = parse(&decrypted, LyricsRawTypes::Krc).expect("解析失败");
println!("解析得到 {} 行歌词", data.lines.as_ref().map_or(0, Vec::len));
}
}若输入为未编码的文件原始字节切片(&[u8]),可直接调用 lyrics_helper::decrypter::decrypter::krc::decrypter::decrypt_lyrics_from_file(&bytes)。
QrcDecrypter 与 KrcDecrypter 实现 LyricsDecrypter trait,其 decrypt() 方法返回 Result<String, DecryptError>:
use lyrics_helper::traits::{DecryptError, LyricsDecrypter};
use lyrics_helper::{KrcDecrypter, QrcDecrypter};
fn main() {
let krc_content = "a3JjMTidGsglTQAO96N6R6CsQj70xu/m37M169y3v7RPU+Do3QAL+VO6caa00kJo1dGLHMwLQ\
P1Sv7SlsM90FOeOblfHU2Y=";
assert!(KrcDecrypter.decrypt(krc_content).is_ok());
// 格式不符:非十六进制
assert_eq!(QrcDecrypter.decrypt("not_hex"), Err(DecryptError::InvalidInput));
// 解密数据无法通过 zlib 解压
assert_eq!(QrcDecrypter.decrypt("00"), Err(DecryptError::DecompressionFailed));
}DecryptError 实现了 Copy + Eq + Display + Error,包含三种失败原因:
-
InvalidInput:Base64/十六进制解码失败,或输入数据长度不足(如未满 4 字节或非 8 字节整倍数)。 -
DecompressionFailed:数据解密后无法通过 zlib 解压。 -
InvalidEncoding:解压后的字节流不是合法的 UTF-8 文本。
| 格式 | 对称算法 | 压缩方式 | 输入特征 |
|---|---|---|---|
| QRC | Triple DES (3DES-EDE,24 字节密钥) | zlib | 十六进制文本或密文字节 |
| KRC | 逐字节 XOR (16 字节密钥) | zlib | Base64 文本或以 krc1 开头的二进制流 |
解密核心实现在 lyrics-crypto crate 内,Triple DES 与 XOR 均为自主实现,无需引入额外重量级加密库;zlib 解压由 flate2 支持。