Skip to content

feat: Add xeapi Aegis support#175

Draft
MoeFurina wants to merge 1 commit into
mainfrom
feat/xeapi-crypto
Draft

feat: Add xeapi Aegis support#175
MoeFurina wants to merge 1 commit into
mainfrom
feat/xeapi-crypto

Conversation

@MoeFurina
Copy link
Copy Markdown
Member

@MoeFurina MoeFurina commented May 23, 2026

由于缺少AES密钥和ECC公钥, 这个PR随时可能关闭

@MoeFurina MoeFurina linked an issue May 23, 2026 that may be closed by this pull request
@vercel
Copy link
Copy Markdown

vercel Bot commented May 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-enhanced Ready Ready Preview, Comment May 23, 2026 4:04pm

@MoeFurina MoeFurina self-assigned this May 23, 2026
@MoeFurina MoeFurina added 增强 Enhancements New feature or request 需要技术帮助 PR Welcome Extra attention is needed labels May 23, 2026
Comment thread util/xeapi.js
* @param {string} input - XOR 编码后的 base64 输入
* @returns {Buffer} 解码后的原始字节
*/
function xorDecode(input) {
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the xeapi (Aegis) encryption scheme, which involves a three-layer encryption process (AES-256-GCM, ECDH P-256, and HKDF-SHA256) reverse-engineered from the Netease Cloud Music Android app. The changes include detailed documentation of the algorithm, a new utility for encryption/decryption, integration into the core request logic, and a new VIP tasks endpoint. Feedback from the reviewer highlights a compatibility issue with Node.js versions regarding crypto.hkdfSync, an invalid hex string length for the static AES key, and the use of placeholder values for the HKDF salt that will prevent successful server communication. Additionally, the reviewer suggested improving error handling for missing public keys and adopting modern JavaScript scoping practices.

Comment thread util/xeapi.js
const sharedSecret = ecdh.computeSecret(serverPublicKey)

// HKDF-SHA256 派生
const derivedKey = crypto.hkdfSync(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

crypto.hkdfSync was introduced in Node.js v15.0.0. However, the package.json specifies a minimum Node.js version of >=12. This will cause a runtime error on older Node.js versions. Please update the engines field in package.json to >=15.0.0 or provide a fallback implementation for HKDF.

Comment thread util/xeapi.js
}

// 参考值 (issue.md 提供, 可能不完整)
const keyHex = 'b31d1a4bf2ba849fe97edd55727d896dc1ed9ee492c0e86947c6dfb93b1'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The hex string keyHex has an odd length (59 characters), which is invalid for a hex-encoded buffer. This results in a truncated 29-byte buffer instead of the expected 32-byte (256-bit) AES key. Please verify and provide the complete 64-character hex string.

Comment thread util/xeapi.js
Comment on lines +273 to +282
if (!serverPublicKeyBase64) {
console.warn(
'[xeapi] ⚠️ 服务器公钥为空,使用临时密钥占位 (此加密无法被真实服务器解密)',
)
const tempEcdh = crypto.createECDH('prime256v1')
tempEcdh.generateKeys()
serverPublicKeyBase64 = tempEcdh
.getPublicKey(null, 'compressed')
.toString('base64')
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Generating a random ECC key pair when the server public key is missing will result in an encrypted payload that the server cannot decrypt, leading to a failed request. It is better to throw an error early to inform the user that a valid serverPublicKey is required for xeapi encryption.

  if (!serverPublicKeyBase64) {
    throw new Error('[xeapi] 服务器公钥未设置!xeapi 加密需要有效的服务器 ECC 公钥。')
  }

Comment thread util/request.js
options.xeapiServerKey || process.env.XEAPI_SERVER_PUBLIC_KEY || '',
})
encryptData = xeapiResult.params // { B, S, R }
var xeapiDynamicKey = xeapiResult.dynamicKey // 用于响应解密
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable xeapiDynamicKey is declared with var inside a switch case. While this works due to function-level hoisting (allowing it to be accessed in the .then block later), it is considered poor practice in modern JavaScript. It is recommended to declare the variable using let at the top of the createRequest function scope to improve clarity and avoid potential hoisting-related bugs.

Comment thread util/xeapi.js
* 🟡 待从 libAegisSDK.so DAT_001a04c0 提取 (Ghidra read_memory)
* 这是一个 16 字节的全局数据,目前使用占位符
*/
const HKDF_SALT = Buffer.alloc(16, 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

HKDF_SALT is currently a placeholder (all zeros). According to the reverse engineering notes in issue.md, this value needs to be extracted from the native library (DAT_001a04c0) for the encryption to be compatible with the actual server. Using a zeroed salt will result in incorrect derived keys.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

增强 Enhancements New feature or request 需要技术帮助 PR Welcome Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PR Welcome] 关于 xeapi 算法

1 participant