2022-11-20 14:30:56 +00:00
|
|
|
|
import QmcCryptoModule from '@/QmcWasm/QmcWasmBundle';
|
2021-12-19 23:03:46 +00:00
|
|
|
|
import { MergeUint8Array } from '@/utils/MergeUint8Array';
|
2021-12-15 13:53:50 +00:00
|
|
|
|
|
2021-12-15 19:59:06 +00:00
|
|
|
|
// 每次处理 2M 的数据
|
2022-11-20 14:30:56 +00:00
|
|
|
|
const DECRYPTION_BUF_SIZE = 2 *1024 * 1024;
|
2021-12-15 13:53:50 +00:00
|
|
|
|
|
2022-11-20 14:30:56 +00:00
|
|
|
|
export interface QMCDecryptionResult {
|
2021-12-25 12:07:14 +00:00
|
|
|
|
success: boolean;
|
|
|
|
|
data: Uint8Array;
|
|
|
|
|
songId: string | number;
|
|
|
|
|
error: string;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-15 13:53:50 +00:00
|
|
|
|
/**
|
2022-11-20 14:30:56 +00:00
|
|
|
|
* 解密一个 QMC 加密的文件。
|
2021-12-15 13:53:50 +00:00
|
|
|
|
*
|
2021-12-15 19:59:06 +00:00
|
|
|
|
* 如果检测并解密成功,返回解密后的 Uint8Array 数据。
|
2022-11-20 14:30:56 +00:00
|
|
|
|
* @param {ArrayBuffer} qmcBlob 读入的文件 Blob
|
2021-12-15 13:53:50 +00:00
|
|
|
|
*/
|
2022-11-20 14:30:56 +00:00
|
|
|
|
export async function DecryptQmcWasm(qmcBlob: ArrayBuffer, ext: string): Promise<QMCDecryptionResult> {
|
|
|
|
|
const result: QMCDecryptionResult = { success: false, data: new Uint8Array(), songId: 0, error: '' };
|
2021-12-25 12:07:14 +00:00
|
|
|
|
|
2021-12-15 13:53:50 +00:00
|
|
|
|
// 初始化模组
|
2022-11-20 14:30:56 +00:00
|
|
|
|
let QmcCrypto: any;
|
2021-12-25 12:07:47 +00:00
|
|
|
|
|
|
|
|
|
try {
|
2022-11-20 14:30:56 +00:00
|
|
|
|
QmcCrypto = await QmcCryptoModule();
|
2021-12-25 12:07:47 +00:00
|
|
|
|
} catch (err: any) {
|
|
|
|
|
result.error = err?.message || 'wasm 加载失败';
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-11-20 14:30:56 +00:00
|
|
|
|
if (!QmcCrypto) {
|
|
|
|
|
result.error = 'wasm 加载失败';
|
|
|
|
|
return result;
|
2021-12-25 12:07:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-20 14:30:56 +00:00
|
|
|
|
// 申请内存块,并文件末端数据到 WASM 的内存堆
|
|
|
|
|
const qmcBuf = new Uint8Array(qmcBlob);
|
|
|
|
|
const pQmcBuf = QmcCrypto._malloc(DECRYPTION_BUF_SIZE);
|
|
|
|
|
QmcCrypto.writeArrayToMemory(qmcBuf.slice(-DECRYPTION_BUF_SIZE), pQmcBuf);
|
|
|
|
|
|
|
|
|
|
// 进行解密初始化
|
|
|
|
|
ext = '.' + ext;
|
|
|
|
|
const tailSize = QmcCrypto.preDec(pQmcBuf, DECRYPTION_BUF_SIZE, ext);
|
|
|
|
|
if (tailSize == -1) {
|
|
|
|
|
result.error = QmcCrypto.getError();
|
2021-12-25 12:07:14 +00:00
|
|
|
|
return result;
|
2022-11-20 14:30:56 +00:00
|
|
|
|
} else {
|
|
|
|
|
result.songId = QmcCrypto.getSongId();
|
|
|
|
|
result.songId = result.songId == "0" ? 0 : result.songId;
|
2021-12-15 19:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const decryptedParts = [];
|
|
|
|
|
let offset = 0;
|
2022-11-20 14:30:56 +00:00
|
|
|
|
let bytesToDecrypt = qmcBuf.length - tailSize;
|
2021-12-15 19:59:06 +00:00
|
|
|
|
while (bytesToDecrypt > 0) {
|
|
|
|
|
const blockSize = Math.min(bytesToDecrypt, DECRYPTION_BUF_SIZE);
|
|
|
|
|
|
|
|
|
|
// 解密一些片段
|
2022-11-20 14:30:56 +00:00
|
|
|
|
const blockData = new Uint8Array(qmcBuf.slice(offset, offset + blockSize));
|
|
|
|
|
QmcCrypto.writeArrayToMemory(blockData, pQmcBuf);
|
|
|
|
|
decryptedParts.push(QmcCrypto.HEAPU8.slice(pQmcBuf, pQmcBuf + QmcCrypto.decBlob(pQmcBuf, blockSize, offset)));
|
2021-12-15 13:53:50 +00:00
|
|
|
|
|
2021-12-15 19:59:06 +00:00
|
|
|
|
offset += blockSize;
|
|
|
|
|
bytesToDecrypt -= blockSize;
|
2021-12-15 13:53:50 +00:00
|
|
|
|
}
|
2022-11-20 14:30:56 +00:00
|
|
|
|
QmcCrypto._free(pQmcBuf);
|
2021-12-15 19:59:06 +00:00
|
|
|
|
|
2021-12-25 12:07:14 +00:00
|
|
|
|
result.data = MergeUint8Array(decryptedParts);
|
2022-11-20 14:30:56 +00:00
|
|
|
|
result.success = true;
|
2021-12-25 12:07:14 +00:00
|
|
|
|
|
|
|
|
|
return result;
|
2021-12-15 22:20:53 +00:00
|
|
|
|
}
|