前言

  1. 网页版用的是 weapi,两个参数,RSA + AES-CBC:

随机生成一个AES密钥,用RSA公钥加密,为参数1;实际请求参数先用一个固定密钥AES加密一次,再用随机生成的AES密钥加密一次,为参数2

  1. 客户端(UWP/Win/Mac/Android)用的是 eapi,一个参数,AES-ECB:

固定的AES密钥,加密请求参数,部分返回数据也用同样的密钥加密过

  1. Linux客户端用的是linux forward api,一个参数,AES-ECB:

固定的AES密钥,加密请求参数,返回数据都没有加密

三者里的固定AES密钥都不一样,eapi 的密钥是 e82ckenh8dichen8

加密

python 实现

安装 cryptography

1
pip install cryptography
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import json
from hashlib import md5
from random import randrange
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

# 将字节数据 data 转换为十六进制字符串
def HexDigest(data):
return "".join([hex(d)[2:].zfill(2) for d in data])

# 计算输入文本 text 的 MD5 哈希值,并返回字节形式的哈希值
def HashDigest(text):
HASH = md5(text.encode("utf-8"))
return HASH.digest()

# 计算输入文本 text 的 MD5 哈希值,并将其转换为十六进制字符串
def HashHexDigest(text):
return HexDigest(HashDigest(text))

# 加密
def eapi_encrypt(AES_KEY, url, payload):
digest = HashHexDigest(f"nobody{url}use{json.dumps(payload)}md5forencrypt")
params = f"{url}-36cd479b6b5-{json.dumps(payload)}-36cd479b6b5-{digest}"
padder = padding.PKCS7(algorithms.AES(AES_KEY).block_size).padder()
padded_data = padder.update(params.encode()) + padder.finalize()
cipher = Cipher(algorithms.AES(AES_KEY), modes.ECB())
encryptor = cipher.encryptor()
enc = encryptor.update(padded_data) + encryptor.finalize()
params = HexDigest(enc)
return params

url = ""
url_param = "/api/playlist/update/playcount"
AES_KEY = b"e82ckenh8dichen8"

headers = {
"Host": "music.163.com",
"user-agent": "NeteaseMusic/5.1.0.1523361492(116);Dalvik/2.1.0 (Linux; U; Android 14; Redmi K80 Pro Build/SKQ1.211006.001)",
"content-type": "application/x-www-form-urlencoded",
"content-length": "2823",
"accept-encoding": "gzip"
}
payload = {
"id": "",
"header": {
"osver": "14",
"deviceId": "",
"appver": "5.1.0",
"ntes_kaola_ad": "1",
"versioncode": "116",
"mobilename": "RedmiK80Pro",
"buildver": "1523361492",
"resolution": "2400x1080",
"__csrf": "",
"NMTID": "",
"os": "android",
"channel": "google",
"MUSIC_A": "",
"requestId": str(randrange(20000000, 30000000))
},
"e_r": "true"
}
cookies = {

}

params = eapi_encrypt(AES_KEY, url_param, payload)
response = requests.post(url, headers=headers, data={"params": params}, cookies=cookies)
print(response.text)

解密

在线AES解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def decrypt_aes_ecb(enc_data, key):
# 创建 AES 解密器
cipher = Cipher(algorithms.AES(key), modes.ECB())
decryptor = cipher.decryptor()

# 解密数据
decrypted_padded_data = decryptor.update(enc_data) + decryptor.finalize()

# 去填充
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
unpadded_data = unpadder.update(decrypted_padded_data) + unpadder.finalize()

return unpadded_data.decode('utf-8')



response_daily = requests.post(url_daily, headers=headers, data={"params": params_daily}, cookies=cookies)
response_daily_decrypt = decrypt_aes_ecb(response_daily.content, AES_KEY)
print(response_daily_decrypt)