# -*- 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')}")