Files
live-hub-py/core/huya/nonce_forge.py
T
yml2213 da2cf5a61d feat(huya): 整合 App 协议登录获取 Cookie 全链路并与 Web 登录解耦
- core/huya: 新增 app_login, wup_encoder, nonce_forge, cert_forge, envelope_forge, device_profile, udb_aes
- core/huya/__init__.py: 导出 login_huya_app_password 与 HuyaAppPasswordLogin
- web/backend: 新增 /accounts/app-password-login 与 /accounts/app-password-login/selected 路由及 Schema,与原 Web 密码登录独立分开
- web/frontend: 增加 App 登录 API 与前端界面“App 登录选中”操作,弹窗结果明确区分
- tests: 新增 test_huya_app_login.py 单元测试覆盖全链路
2026-08-26 15:51:30 +08:00

79 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""虎牙证书 nonce(rnd) 本地生成器。
基于 XXTEA 算法与 uid + k1 派生密钥。
"""
from __future__ import annotations
import hashlib
import struct
import time
K1_DEFAULT = "865a4924a40897ac1fcfe6b4c2cbb0e3"
def _xxtea_encrypt_words(v: list[int], k: list[int]) -> list[int]:
"""标准 XXTEA (delta=0x9e3779b9, rounds=6+52/n)。"""
n = len(v)
if n < 2:
return v
z = v[n - 1]
y = v[0]
s = 0
delta = 0x9E3779B9
q = 6 + 52 // n
while q > 0:
s = (s + delta) & 0xFFFFFFFF
e = (s >> 2) & 3
p = 0
while p < n - 1:
y = v[p + 1]
z = (v[p] + ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
^ ((s ^ y) + (k[(p & 3) ^ e] ^ z)))) & 0xFFFFFFFF
v[p] = z
p += 1
y = v[0]
z = (v[n - 1] + ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)))
^ ((s ^ y) + (k[((n - 1) & 3) ^ e] ^ z)))) & 0xFFFFFFFF
v[n - 1] = z
q -= 1
return v
def xxtea_encrypt(data: bytes, key16: bytes) -> bytes:
"""虎牙专用 XXTEA: 输出 words = ceil(len/4)+1, 末尾 word 存原始长度。"""
n = len(data)
nwords = (n // 4) + 1
v = [0] * nwords
for i in range(n // 4):
v[i] = struct.unpack("<I", data[i * 4:i * 4 + 4])[0]
v[nwords - 1] = n
k = [struct.unpack("<I", key16[i * 4:i * 4 + 4])[0] for i in range(4)]
_xxtea_encrypt_words(v, k)
return b"".join(struct.pack("<I", w & 0xFFFFFFFF) for w in v)
def pack_u64(v: int) -> bytes:
"""8字节小端裸值。"""
return struct.pack("<Q", v & 0xFFFFFFFFFFFFFFFF)
def gen_nonce(
uid: int,
k1: str = K1_DEFAULT,
service_time_ms: int | None = None,
counter: int = 0,
) -> bytes:
"""按设备算法生成 20B nonce(rnd)。
- uid: 虎牙 uid 数字(如 1199666914671
- k1: 设备常量 32hex
- service_time_ms: 缺省为当前毫秒时间戳
- counter: 计数器(通常为 0
"""
st = service_time_ms if service_time_ms is not None else int(time.time() * 1000)
st &= 0x7FFFFFFFFFFF
nonce_val = (counter & 0xFFFF) | (st << 16)
data = pack_u64(st) + pack_u64(nonce_val)
key = hashlib.md5((str(uid) + k1).encode()).hexdigest()[:16].encode()
return xxtea_encrypt(data, key)