fix: treat qmcflac/qmcogg as QMCv2 and fallback to QMCv1

(cherry picked from commit 41e588e9864801897fa13eb96a1764baaa5a4ab5)
This commit is contained in:
鲁树人 2021-12-15 22:07:05 +00:00 committed by MengYX
parent 9edcaadb83
commit 1e927ad962
No known key found for this signature in database
GPG Key ID: E63F9C7303E8F604
2 changed files with 23 additions and 11 deletions

View File

@ -27,11 +27,14 @@ export const HandlerMap: { [key: string]: Handler } = {
"mflac": {ext: "flac", version: 2}, "mflac": {ext: "flac", version: 2},
"mflac0": {ext: "flac", version: 2}, "mflac0": {ext: "flac", version: 2},
// qmcflac / qmcogg:
// 有可能是 v2 加密但混用同一个后缀名。
"qmcflac": {ext: "flac", version: 2},
"qmcogg": {ext: "ogg", version: 2},
"qmc0": {ext: "mp3", version: 1}, "qmc0": {ext: "mp3", version: 1},
"qmc2": {ext: "ogg", version: 1}, "qmc2": {ext: "ogg", version: 1},
"qmc3": {ext: "mp3", version: 1}, "qmc3": {ext: "mp3", version: 1},
"qmcogg": {ext: "ogg", version: 1},
"qmcflac": {ext: "flac", version: 1},
"bkcmp3": {ext: "mp3", version: 1}, "bkcmp3": {ext: "mp3", version: 1},
"bkcflac": {ext: "flac", version: 1}, "bkcflac": {ext: "flac", version: 1},
"tkm": {ext: "m4a", version: 1}, "tkm": {ext: "m4a", version: 1},
@ -45,16 +48,26 @@ export const HandlerMap: { [key: string]: Handler } = {
export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise<DecryptResult> { export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise<DecryptResult> {
if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`; if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`;
const handler = HandlerMap[raw_ext]; const handler = HandlerMap[raw_ext];
let { version } = handler;
const fileBuffer = await GetArrayBuffer(file); const fileBuffer = await GetArrayBuffer(file);
let musicDecoded: Uint8Array; let musicDecoded: Uint8Array|undefined;
if (handler.version === 1) {
if (version === 2) {
const v2Decrypted = await DecryptQMCv2(fileBuffer);
// 如果 v2 检测失败,降级到 v1 再尝试一次
if (v2Decrypted) {
musicDecoded = v2Decrypted;
} else {
version = 1;
}
}
if (version === 1) {
const seed = QmcMaskGetDefault(); const seed = QmcMaskGetDefault();
musicDecoded = seed.Decrypt(new Uint8Array(fileBuffer)); musicDecoded = seed.Decrypt(new Uint8Array(fileBuffer));
} else if (handler.version === 2) { } else if (!musicDecoded) {
musicDecoded = await DecryptQMCv2(fileBuffer); throw new Error(`解密失败: ${raw_ext}`);
} else {
throw new Error(`不支持的加密版本: ${handler.version} (${raw_ext})`);
} }
const ext = SniffAudioExt(musicDecoded, handler.ext); const ext = SniffAudioExt(musicDecoded, handler.ext);

View File

@ -28,7 +28,7 @@ function MergeUint8Array(array: Uint8Array[]): Uint8Array {
* Uint8Array * Uint8Array
* @param {ArrayBuffer} mggBlob Blob * @param {ArrayBuffer} mggBlob Blob
* @param {string} name * @param {string} name
* @return {Promise<Uint8Array|null>} * @return {Promise<Uint8Array|false>}
*/ */
export async function DecryptQMCv2(mggBlob: ArrayBuffer) { export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
// 初始化模组 // 初始化模组
@ -53,14 +53,13 @@ export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
// (pos: i32; len: i32; error: char[??]) // (pos: i32; len: i32; error: char[??])
const position = QMCCrypto.getValue(pDetectionResult, "i32"); const position = QMCCrypto.getValue(pDetectionResult, "i32");
const len = QMCCrypto.getValue(pDetectionResult + 4, "i32"); const len = QMCCrypto.getValue(pDetectionResult + 4, "i32");
const detectionError = QMCCrypto.UTF8ToString(pDetectionResult + 8);
// 释放内存 // 释放内存
QMCCrypto._free(pDetectionBuf); QMCCrypto._free(pDetectionBuf);
QMCCrypto._free(pDetectionResult); QMCCrypto._free(pDetectionResult);
if (!detectOK) { if (!detectOK) {
throw new Error("解密失败: \n " + detectionError); return false;
} }
// 计算解密后文件的大小。 // 计算解密后文件的大小。