Files

90 lines
2.4 KiB
Python
Raw Permalink 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)