From 117351a6e57917d0c048a5f814ee90e686dee7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=81=E6=A0=91=E4=BA=BA?= Date: Mon, 22 May 2023 23:07:58 +0100 Subject: [PATCH] feat: added support for ncm (#15) --- package.json | 2 +- pnpm-lock.yaml | 8 ++++---- src/decrypt-worker/crypto/CryptoFactory.ts | 4 ++++ src/decrypt-worker/crypto/ncm/ncm_pc.key.ts | 2 ++ src/decrypt-worker/crypto/ncm/ncm_pc.ts | 21 +++++++++++++++++++++ 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/decrypt-worker/crypto/ncm/ncm_pc.key.ts create mode 100644 src/decrypt-worker/crypto/ncm/ncm_pc.ts diff --git a/package.json b/package.json index fe0b076..c5a1981 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@chakra-ui/react": "^2.6.1", "@emotion/react": "^11.11.0", "@emotion/styled": "^11.11.0", - "@jixun/libparakeet": "0.0.0-exp.18", + "@jixun/libparakeet": "0.0.0-exp.19", "@reduxjs/toolkit": "^1.9.5", "framer-motion": "^10.12.12", "nanoid": "^4.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 781287d..f3aeb38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,8 +14,8 @@ dependencies: specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.0)(@types/react@18.2.6)(react@18.2.0) '@jixun/libparakeet': - specifier: 0.0.0-exp.18 - version: 0.0.0-exp.18 + specifier: 0.0.0-exp.19 + version: 0.0.0-exp.19 '@reduxjs/toolkit': specifier: ^1.9.5 version: 1.9.5(react-redux@8.0.5)(react@18.2.0) @@ -3060,9 +3060,9 @@ packages: chalk: 4.1.2 dev: true - /@jixun/libparakeet@0.0.0-exp.18: + /@jixun/libparakeet@0.0.0-exp.19: resolution: - { integrity: sha512-KLUCxr6x47hDs1tszY8uyR8fgiB+b2UIFSgCg9GEs+AiB+oFTyQlhZXbKmyfDOuWSDiBcdKJvmXq29x3zPDNEQ== } + { integrity: sha512-FePuE49fCIRppzTJzaeISJhtvf1mFyU4MpVlQigmlR2CLAXtEkJz0HhsoumJwzcWv6UQJMUSagtXoTa8pxZ4ww== } dev: false /@jridgewell/gen-mapping@0.3.3: diff --git a/src/decrypt-worker/crypto/CryptoFactory.ts b/src/decrypt-worker/crypto/CryptoFactory.ts index afe390f..124104a 100644 --- a/src/decrypt-worker/crypto/CryptoFactory.ts +++ b/src/decrypt-worker/crypto/CryptoFactory.ts @@ -1,4 +1,5 @@ import { CryptoFactory } from './CryptoBase'; +import { NCMCrypto } from './ncm/ncm_pc'; import { QMC1Crypto } from './qmc/qmc_v1'; import { QMC2Crypto } from './qmc/qmc_v2'; @@ -12,6 +13,9 @@ export const allCryptoFactories: CryptoFactory[] = [ // QMCv2 (*.mflac) QMC2Crypto.make, + // NCM (*.ncm) + NCMCrypto.make, + // Crypto that does not implement "checkBySignature" or need to decrypt the entire file and then check audio type, // should be moved to the bottom of the list for performance reasons. diff --git a/src/decrypt-worker/crypto/ncm/ncm_pc.key.ts b/src/decrypt-worker/crypto/ncm/ncm_pc.key.ts new file mode 100644 index 0000000..173e640 --- /dev/null +++ b/src/decrypt-worker/crypto/ncm/ncm_pc.key.ts @@ -0,0 +1,2 @@ +export const NCM_KEY = 'hzHRAmso5kInbaxW'; +export const NCM_MAGIC_HEADER = new Uint8Array([0x43, 0x54, 0x45, 0x4e, 0x46, 0x44, 0x41, 0x4d]); diff --git a/src/decrypt-worker/crypto/ncm/ncm_pc.ts b/src/decrypt-worker/crypto/ncm/ncm_pc.ts new file mode 100644 index 0000000..15e094b --- /dev/null +++ b/src/decrypt-worker/crypto/ncm/ncm_pc.ts @@ -0,0 +1,21 @@ +import { transformBlob } from '~/decrypt-worker/util/transformBlob'; +import type { CryptoBase } from '../CryptoBase'; +import { NCM_KEY, NCM_MAGIC_HEADER } from './ncm_pc.key'; + +export class NCMCrypto implements CryptoBase { + cryptoName = 'NCM/PC'; + checkByDecryptHeader = false; + + async checkBySignature(buffer: ArrayBuffer) { + const view = new DataView(buffer, 0, NCM_MAGIC_HEADER.byteLength); + return NCM_MAGIC_HEADER.every((value, i) => value === view.getUint8(i)); + } + + async decrypt(buffer: ArrayBuffer): Promise { + return transformBlob(buffer, (p) => p.make.NeteaseNCM(NCM_KEY)); + } + + public static make() { + return new NCMCrypto(); + } +}