feat(ncm): 网易云核心库 core/ (agent-203) — ncm_http(mbedtls TLS1.2+chunked+流式限幅)/ncm_crypto(eapi/weapi/linuxapi, RSA raw逐字节验证)/ncm_login(unikey→二维码→轮询状态机→cookie加密落盘)/ncm_api(歌单/详情/播放地址Hi-res逐档降级/歌词)/ncm_cache(LRU 默认10G)/ncm_store(deviceId持久化+机器密钥)
宿主+qemu-mipsel 全链路 PASS(unikey实拿/801轮询/eapi往返/RSA对拍/缓存LRU); -Wall -Wextra 自有代码0warning 待联调: 803真扫码、真机 hw:0,0 播放链路
This commit is contained in:
1 parent
85b4aea24f
commit
8012948b26
25 files changed
+3416
No files matched your search
@@ -122,3 +122,97 @@ CA bundle 内置方案、音质档位映射实测。这些属设备/账号侧联
|
||||
- **推荐 TLS/加密一体用 mbedtls**(单库一次解决 TLS + AES/MD5/RSA raw/Base64 + X509,规避 RNSS-raw 手写风险);BearSSL 为省 flash 备选。
|
||||
- **v1 体积增量 ≈ 438 KB(库)/ 只做 mp3**,内存估计数百 KB 工作集,14MB 可行;主要优化点是 mbedtls 裁剪与封面限幅。
|
||||
- **最关键风险(RSA raw)已验证**;其余风险集中在风控(deviceId/UA 稳定持久化)与无版权降级策略。
|
||||
|
||||
---
|
||||
|
||||
## 9. 核心库批次(core/,纯 C 静态库,无 UI)
|
||||
|
||||
> 日期:2026-08-31。在 §1-8 预研(候选库/工具链已定型)基础上落地核心库:http/crypto/login/api/cache 五模块
|
||||
> + 公共/存储/JSON/请求构建支撑模块 + ncm_ctx 上下文。仅改动 `patch_v2/ncm_app/`。未 commit/push/刷机/动设备。
|
||||
|
||||
### 9.1 模块与公开 API(头文件签名)
|
||||
|
||||
| 模块 | 文件 | 主要公开函数 |
|
||||
|---|---|---|
|
||||
| 公共工具 | `core/ncm_common.h/.c` | `ncm_hex_encode/decode` `ncm_b64_encode/decode` `ncm_md5_hex` `ncm_sha256_hex` `ncm_url_encode/decode` `ncm_random_bytes` `ncm_now_ms` 等 |
|
||||
| JSON | `core/ncm_json.h/.c` | `ncm_json_parse` `ncm_json_obj_get` `ncm_json_arr_get/len` `ncm_json_path[_str/_int/_bool]` `ncm_json_get_str_at/get_int_at` |
|
||||
| HTTP | `core/ncm_http.h/.c` | `ncm_http_request`(一次性 POST/GET,限幅)`ncm_http_download`(流式回调 + max_bytes)`ncm_http_parse_set_cookie` `ncm_http_set_verify_default` |
|
||||
| 存储 | `core/ncm_store.h/.c` | `ncm_store_init` `ncm_store_get/set_device_id` `ncm_store_machine_key` `ncm_store_cookie_encrypt/decrypt` `ncm_store_save/load/clear_session` `ncm_store_write/read_file` `ncm_store_read_cfg_int` |
|
||||
| 加密 | `core/ncm_crypto.h/.c` | `ncm_crypto_eapi` `ncm_crypto_weapi` `ncm_crypto_linuxapi` `ncm_crypto_rsa_raw_selfcheck` |
|
||||
| 请求构建 | `core/ncm_req.h/.c` | `ncm_req_build`(eapi/weapi/linux,注入 header/csrf_token/UA/Cookie)`ncm_req_cookie_get` |
|
||||
| 登录 | `core/ncm_login.h/.c` | `ncm_login_qr_url` `ncm_login_unikey` `ncm_login_qr_matrix`(qrcodegen)`ncm_login_poll` `ncm_login_status_check` `ncm_login_save/load/clear_cookie` |
|
||||
| 歌单/播放 | `core/ncm_api.h/.c` | `ncm_api_user_playlist` `ncm_api_playlist_detail` `ncm_api_song_detail` `ncm_api_song_url` `ncm_api_song_url_auto` `ncm_api_lyric` `ncm_api_level_str` |
|
||||
| 缓存 | `core/ncm_cache.h/.c` | `ncm_cache_init` `ncm_cache_set_limit_gb/limit_gb` `ncm_cache_load_setting` `ncm_cache_lookup` `ncm_cache_open/write/commit/abort` `ncm_cache_total_bytes` `ncm_cache_evict` `ncm_cache_path` |
|
||||
| 上下文 | `core/ncm.h` + `ncm_ctx.c` | `ncm_ctx_t`(deviceId/cookie/CA/默认音质/cache)`ncm_ctx_init` `ncm_ctx_set/load/clear_cookie` `ncm_ctx_default_cache_dir` |
|
||||
|
||||
关键常量:`NCM_EAPI_KEY`/`NCM_WEAPI_PRESET`/`NCM_WEAPI_IV`/`NCM_LINUXAPI_KEY`/`NCM_RSA_DER_B64`(`ncm_crypto.h`);
|
||||
UA 按加密类型分流(eapi=iPhone `NeteaseMusic 9.0.90/5038`,weapi=Chrome/Edg 124),请求头注入对齐 CNMPlayer `request.rs`(deviceId/UA 稳定)。
|
||||
|
||||
### 9.2 关键实现取舍
|
||||
- **CA 方案**(`ncm_http.h` 注释):`verify_ca=1`(默认)加载系统 CA bundle(或 `ca_path`),失败即拒绝(防 MITM);`verify_ca=0` 跳过校验(仅调试/受限网)。全局默认由 `ncm_http_set_verify_default` 设定,`ncm_ctx_init` 以其 `verify_ca/ca_path` 设置。**设备侧需内置 CA 根**(VENDOR_NOTES §备注),否则接口 eapi/weapi 会被拒。
|
||||
- **RSA raw**:用 `mbedtls_rsa_public()` 无 padding 纯模幂,16 字节 secret 右对齐 128 字节(前导 0),输出 256 小写 hex——已与 Python `pow(m,e,n)` 逐字节一致(见 9.4)。
|
||||
- **weapi**:双层 AES-128-CBC(`params` base64,含 `+/=` 需 urlencode)+ RSA(raw) 加密随机 16 位 base62 密钥(RSA 前**反转**)。
|
||||
- **会话cookie**:加密落盘 `MeowData/<pkg>/data/session.enc`,密钥 = `sha256(MAC + 盐)`;无 MAC(qemu/无网卡)回退到设备私有 `.mkey` 派生。**仅为防裸读模糊,非真安全**(头文件已注明)。
|
||||
- **缓存**:目录默认 `MeowData/os.meow.ncm/cache/`;上限默认 10GB(1~100 可配),读设置键 `ncm.cache_limit_gb`(`<data_dir>/ncm.cache_limit_gb.cfg`,对齐 SDK meow_config);LRU 按文件 mtime,`ncm_cache_lookup/commit` 刷新;命中即离线可播。
|
||||
- **音质**:`ncm_api_song_url_auto` 从 desired(默认 Hi-res)往下降级 `hires→lossless→exhigh→higher→standard`,只返回可解码 mp3(url 非空且 type=mp3);无该档对当前歌曲降级。
|
||||
|
||||
### 9.3 构建
|
||||
`./build_core.sh` → `out/core-host/`、`core-mipsel/`(自有代码对象 + vendor qrcodegen + jsmn 唯一实现 TU),链接 `out/mbedtls/{host,mipsel}/*.a`,产出:
|
||||
- `test/test_ncm_core_host`(宿主,可跑)
|
||||
- `out/test_ncm_core_mipsel`(mipsel 静态)。`size`:`text 462662 / data 212 / bss 27688`(含测试 printf 基建 + mbedtls + qrcodegen;核心库本身链接更小)。
|
||||
- 自有代码 `-Wall -Wextra` **0 warning**;vendor 警告豁免。mipsel 用 `.tools/zig-mipsel-cc` 静态交叉。
|
||||
|
||||
### 9.4 验证记录(宿主 + qemu-mipsel 双向实测,响应已脱敏/截断)
|
||||
- **unikey 实拿(eapi)**:`{"code":200,"unikey":"<uuid>"}`(宿主 `dc5bd090-…`,qemu-mipsel `ef9a5db2-…`);二维码 URL `https://music.163.com/login?codekey=<uuid>`。
|
||||
- **轮询(未扫码)**:`{"code":801,"message":"等待扫码"}` → `state=等待扫码(801)`,两平台一致。
|
||||
- **login_status(伪造 cookie)**:返回 weapi 可解析 JSON(code 200 但 profile null)→ 库判 `NCM_ERR_AUTH(-13)`,证明 weapi 请求被服务端接受。
|
||||
- **RSA raw 交叉**:`ncm_crypto_rsa_raw_selfcheck` 输出 `55b33e7e…b2b83`,与 Python `pow(m,65537,n)`(§3 已交叉验证值)**逐字节一致**。weapi params 为合法 base64(RSA 封装的 16 字节随机密钥无法无私钥解密,其 AES-CBC 为标准用法)。
|
||||
- **eapi 往返**:`ncm_crypto_eapi` 产物可用 AES-ECB 解回含 `url` + `json` 的明文(`/api/login/qrcode/unikey` + `{"type":3}`)。
|
||||
- **cookie 加解密**:38 字节串 `MUSIC_U=…; __csrf=xyz; os=pc` 加密→解密完全一致(含一次 mbedtls `crypt_cbc` 就地改写 IV 的坑,已修)。
|
||||
- **缓存**:写入/命中/abort 不留档/强制小上限触发 LRU 淘汰(总字节降至 ≤ 上限)。
|
||||
- **二维码**:41×41 内矩阵生成,暗模块 >0。
|
||||
- **无凭据错误处理**:`user_playlist(uid=0,无cookie)` 优雅返回(公开数据或错误码,不崩溃);`song_url(id=0)` 返回无 url。
|
||||
|
||||
### 9.5 md5(自有源码)
|
||||
```
|
||||
778847a8419325af2b95ad0ef7749781 core/ncm_api.h c07d246c9b64e4d3b9078b9e33d19fe4 core/ncm_cache.h
|
||||
6e878566f6a4c4377c98e87e9967fdcc core/ncm_common.h 9056253bfb635d8224e7454c6b1796a2 core/ncm_crypto.h
|
||||
157807f07a96f43249f6aeb9707d053f core/ncm.h 477dd9f5eab61e2940cb432d1b215b3a core/ncm_http.h
|
||||
398e62a0b641f13bc80c02d5e42a0401 core/ncm_json.h 05fb336d3b65b041095bd8fb3c64bc3c core/ncm_login.h
|
||||
96f423ef1a36bda7b5cb3961fbe22028 core/ncm_req.h 02c7ff38dd856455f32a4cc7bbc5edd5 core/ncm_store.h
|
||||
f8f8e96464d3c4ebcf1898eb4212c55a core/jsmn_impl.c a00e9b9b1adf7c6cf924eb9ecfc90a67 core/ncm_common.c
|
||||
e75c29217ef5dd3f0e23c740b79210c1 core/ncm_crypto.c 9ebfa83e31a530b4dc8fd7877c2f5fb9 core/ncm_ctx.c
|
||||
319df449ecd7727f328e01adb518ba57 core/ncm_http.c d69ff302ec111a74f621571818da4622 core/ncm_json.c
|
||||
a53e55f9cab828fd59b694330ec7371e core/ncm_login.c d81eda09640ff748b0a1c14607447d1b core/ncm_req.c
|
||||
1ceda66d30d44a3d8850df2e876c0195 core/ncm_store.c 7cdb84fcf87384eb5125e5aae01eac84 test/test_ncm_core.c
|
||||
94a4dd07fba98a6e7b70021aaeb8cb19 build_core.sh
|
||||
```
|
||||
产物:`test/test_ncm_core_host` md5 `0e41d3d413819768d65d2e9ca9e082ed`;`out/test_ncm_core_mipsel` md5 `e05f1937e5fc49a2590b830c28ee6372`。
|
||||
|
||||
### 9.6 出入清单(只改 `patch_v2/ncm_app/`)
|
||||
```
|
||||
新增:
|
||||
core/ncm.h ncm_ctx.c // 伞头 + 上下文
|
||||
core/ncm_common.h/.c // hex/base64/md5/sha256/urlencode/errcode
|
||||
core/ncm_json.h/.c // jsmn 路径导航
|
||||
core/ncm_crypto.h/.c // eapi/weapi/linuxapi + RSA raw
|
||||
core/ncm_http.h/.c // mbedtls HTTPS POST/GET + CA取舍 + 超时 + chunked
|
||||
core/ncm_store.h/.c // deviceId/MAC机器密钥/cookie加解密/配置读取
|
||||
core/ncm_req.h/.c // 加密请求构建(md5/UA/cookie 注入)
|
||||
core/ncm_login.h/.c // unikey/二维码矩阵/轮询状态机/cookie捕获/login_status
|
||||
core/ncm_api.h/.c // 歌单/详情/歌曲/播放地址/歌词
|
||||
core/ncm_cache.h/.c // LRU 缓存 + 离线可播
|
||||
core/jsmn_impl.c // jsmn 唯一实现 TU(防多 TU 重复定义)
|
||||
test/test_ncm_core.c // 宿主 + mipsel 综合实测
|
||||
build_core.sh // 宿主 + mipsel 编译链接
|
||||
修改:
|
||||
REPORT.md // 追加本批记录
|
||||
(未动 vendor/,未动其余目录)
|
||||
```
|
||||
|
||||
### 9.7 未做/诚实出入
|
||||
- **803 真登录**未实测(需真实扫码):code 803 分支的 set-cookie 捕获/合并逻辑按 document 实现,但未真跑;联调时建议真扫码验证一次 `MUSIC_U` 内容与 `login_status` 校验链路。
|
||||
- **weapi params 无法无 RSA 私钥解密**核验其内部 AES 双层,但 RSA 封路径已逐字节交叉,AES-CBC 为标准用法(可用 CNMPlayer 同源实现比对)。
|
||||
- **播放地址/缓存仅验证到“请求-解析-无版权返回 null”**;未做真实音频下载落盘(缓存 open/write/commit 已由单元测试覆盖;真实 mp3 下载留给带 UI 的播放层用 `ncm_http_download`+`ncm_cache_*` 串联)。
|
||||
- **栈用量**:单次 http 调用涉及 mbedtls ssl/净栈,峰值栈估几十 KB(与预研 demo 同级);App 线程栈需 ≥64KB,联调时以真机线程栈为准。
|
||||
- **JSON 响应限幅**:歌单/歌曲详情走 1MB~2MB 堆缓冲 + token 计数后精确分配,不算常驻;封面/大 JSON 不整体驻留,封面下载另有 `max_bytes` 限幅(建议 ~256KB,未在本次接线)。
|
||||
Reference in new issue
Block a user