You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.8 KiB
152 lines
4.8 KiB
# -*- coding: utf-8 -*-
|
|
import time
|
|
import random
|
|
import struct
|
|
import base64
|
|
import hmac
|
|
import hashlib
|
|
import ctypes
|
|
|
|
class _RC4:
|
|
"""
|
|
内部使用的 RC4 算法实现,还原了 Java 版本特殊的 Key Scheduling 逻辑
|
|
"""
|
|
_RC4_PK = "QrMgt8GGYI6T52ZY5AnhtxkLzb8egpFn3j5JELI8H6wtACbUnZ5cc3aYTsTRbmkAkRJeYbtx92LPBWm7nBO9UIl7y5i5MQNmUZNf5QENurR5tGyo7yJ2G0MBjWvy6iAtlAbacKP0SwOUeUWx5dsBdyhxa7Id1APtybSdDgicBDuNjI0mlZFUzZSS9dmN8lBD0WTVOMz0pRZbR3cysomRXOO1ghqjJdTcyDIxzpNAEszN8RMGjrzyU7Hjbmwi6YNK"
|
|
|
|
def __init__(self):
|
|
self.state = list(range(256))
|
|
self.x = 0
|
|
self.y = 0
|
|
self._prepare_key(self._RC4_PK)
|
|
|
|
def _prepare_key(self, key_str):
|
|
key_len = len(key_str)
|
|
j = 0
|
|
for i in range(256):
|
|
c_char_at = ord(key_str[i % key_len])
|
|
i13 = self.state[i]
|
|
j = (c_char_at + i13 + j) % 256
|
|
self.state[i], self.state[j] = self.state[j], self.state[i]
|
|
self.x = 0
|
|
self.y = 0
|
|
|
|
def rc4(self, data):
|
|
output = bytearray(len(data))
|
|
x = self.x
|
|
y = self.y
|
|
state = list(self.state)
|
|
for k in range(len(data)):
|
|
x = (x + 1) % 256
|
|
sx = state[x]
|
|
y = (y + sx) % 256
|
|
sy = state[y]
|
|
state[x], state[y] = sy, sx
|
|
idx = (state[x] + state[y]) % 256
|
|
output[k] = data[k] ^ state[idx]
|
|
return bytes(output)
|
|
|
|
class _JavaUtils:
|
|
"""
|
|
内部工具类:处理 Python 与 Java 之间的数据类型差异(大端序、溢出处理)
|
|
"""
|
|
@staticmethod
|
|
def get_bytes(val):
|
|
"""Int -> 4 bytes (Big Endian)"""
|
|
return struct.pack('>i', ctypes.c_int32(val).value)
|
|
|
|
@staticmethod
|
|
def string_hashcode(s):
|
|
"""模拟 Java String.hashCode 的溢出行为"""
|
|
h = 0
|
|
for c in s:
|
|
h = (31 * h + ord(c)) & 0xFFFFFFFF
|
|
return ctypes.c_int32(h).value
|
|
|
|
class UTDIDGenerator:
|
|
"""
|
|
UTDID 生成器主类
|
|
"""
|
|
def __init__(self):
|
|
# 初始化配置与 HMAC Key
|
|
self._init_hmac_key()
|
|
|
|
def _init_hmac_key(self):
|
|
MAX_POWER_OF_TWO = 64
|
|
OP_LOAD = 24
|
|
|
|
# 原始 Java 有符号 byte 数组
|
|
raw_b_arr2_signed = [
|
|
69, 114, 116, -33, 125, -54, -31, 86, -11, 11, -78, -96, -17, -99,
|
|
MAX_POWER_OF_TWO,
|
|
23, -95, -126, -82, -64, 113, 116, -16, -103,
|
|
OP_LOAD,
|
|
-30, 9, -39, 33, -80, -68, -78, -117, 53, 30, -122,
|
|
MAX_POWER_OF_TWO,
|
|
-104, 74, -49, 106, 85, -38, -93
|
|
]
|
|
# 转换为无符号
|
|
b_arr2 = bytearray([b + 256 if b < 0 else b for b in raw_b_arr2_signed])
|
|
# 解密出 HMAC Key
|
|
self.hmac_key = _RC4().rc4(b_arr2)
|
|
|
|
def _calc_hmac(self, data):
|
|
h = hmac.new(self.hmac_key, data, hashlib.sha1)
|
|
signature = h.digest()
|
|
return base64.b64encode(signature).decode('utf-8')
|
|
|
|
def _generate_random_imei(self):
|
|
"""生成随机的 15 位数字 IMEI"""
|
|
prefix = random.choice(['35', '86', '01', '99'])
|
|
suffix = "".join([str(random.randint(0, 9)) for _ in range(15 - len(prefix))])
|
|
return prefix + suffix
|
|
|
|
def generate(self, imei=None):
|
|
"""
|
|
生成一个 UTDID
|
|
:param imei: 可选,指定 IMEI 字符串。如果不传则自动随机生成。
|
|
:return: Base64 编码的 UTDID 字符串
|
|
"""
|
|
buffer = bytearray()
|
|
|
|
# 1. Timestamp (4 bytes)
|
|
timestamp = int(time.time())
|
|
buffer.extend(_JavaUtils.get_bytes(timestamp))
|
|
|
|
# 2. Random Int (4 bytes)
|
|
random_int = random.randint(-2147483648, 2147483647)
|
|
buffer.extend(_JavaUtils.get_bytes(random_int))
|
|
|
|
# 3. Version (1 byte) & Reserved (1 byte)
|
|
buffer.append(3)
|
|
buffer.append(0)
|
|
|
|
# 4. IMEI Hash (4 bytes)
|
|
real_imei = imei if imei else self._generate_random_imei()
|
|
imei_hash = _JavaUtils.string_hashcode(real_imei)
|
|
buffer.extend(_JavaUtils.get_bytes(imei_hash))
|
|
|
|
# 5. Checksum (4 bytes)
|
|
# 对应: hashCode(calcHmac(bytes[0:14]))
|
|
data_14 = bytes(buffer)
|
|
hmac_str = self._calc_hmac(data_14)
|
|
hmac_hash = _JavaUtils.string_hashcode(hmac_str)
|
|
buffer.extend(_JavaUtils.get_bytes(hmac_hash))
|
|
|
|
# 6. Final Base64
|
|
return base64.b64encode(buffer).decode('utf-8')
|
|
|
|
# --- 快捷单例导出 ---
|
|
# 实例化一个默认生成器,外部可以直接 import 这个对象或函数
|
|
_default_generator = UTDIDGenerator()
|
|
|
|
def generate_utdid(imei=None):
|
|
"""
|
|
快捷函数:生成 UTDID
|
|
"""
|
|
return _default_generator.generate(imei)
|
|
|
|
# if __name__ == "__main__":
|
|
# # 测试代码
|
|
# print("--- Testing UTDID Generator ---")
|
|
# print(f"Random: {generate_utdid()}")
|
|
# print(f"Fixed: {generate_utdid('865100020000000')}")
|