from functools import reduce import base64 from xhs.shield_const import * """ 小红书 hmac_main 的aes处理 自定义aes 逆向版本 6.97.0.1 """ class AES: def __init__(self, key: bytes): self.aes_type = len(key) * 8 self._key_r = self._generate_key(key) def _sort_key(self, w_list): """ 重新编排key """ def change_char(w): w_4 = self._split_int(w) # 拆分成 4x8bit s_w_4 = [SBox[w_4[0]], SBox[w_4[1]], SBox[w_4[2]], SBox[w_4[3]]] s_s_w_4 = [dword_7F550[s_w_4[0]], dword_7F950[s_w_4[1]], dword_7FD50[s_w_4[2]], dword_80150[s_w_4[3]]] key4 = reduce(lambda x, y: x ^ y, s_s_w_4) return key4 # 交换位置 for i in range(len(w_list) // 2): tmp = w_list[i] if i > 3: # 需要交换位置 tmp = change_char(tmp) w_list[len(w_list) - i - 1] = change_char(w_list[len(w_list) - i -1]) w_list[i] = w_list[len(w_list) - i -1] w_list[len(w_list) - i -1] = tmp # print(i, len(w_list) - i -1) return w_list @staticmethod def hex_string(num, step=2): """ step 控制二进制的长度 避免有些少零了 """ tmp_string = hex(num)[2:] if len(tmp_string) < step: tmp_string = '0' * (step - len(tmp_string)) + tmp_string return tmp_string def encrypt(self, plaintext:bytes): """ 加密 解密 :param plaintext: :return: """ state = [[plaintext[i + j] for j in range(16)] for i in range(0, len(plaintext), 16)] # 先分组 result = [] # 进行加密流程 for p in range(len(state)): _plaintext_block = [self._joint_int(state[p][i:i+4]) for i in range(0, 16, 4)] state[p] = _plaintext_block.copy() # 合并为每四个字节的数组 _encrypt_block = self.encrypt_block(_plaintext_block) # 处理第一块 if p > 0: extra_block = [self.hex_string(_encrypt_block[i] ^ state[p - 1][i], 8) for i in range(4)] # 异或处理 result.append("".join(extra_block)) return "".join(result[:4]) def encrypt_block(self, plaintext_block): """ 按照块加密 """ keys = self._key_r # 第一轮由于明文和那个key是反的 单独计算 plaintext_block[0] = plaintext_block[0] ^ keys[3] plaintext_block[1] = plaintext_block[1] ^ keys[2] plaintext_block[2] = plaintext_block[2] ^ keys[1] plaintext_block[3] = plaintext_block[3] ^ keys[0] for i in range(0, 9): num = (i + 1) * 4 a1 = self._split_int(plaintext_block[0]) # 这块是按顺序的 a2 = self._split_int(plaintext_block[1]) a3 = self._split_int(plaintext_block[2]) a4 = self._split_int(plaintext_block[3]) # 查表法进行替换 a1_1_box = [dword_7F550[a1[0]], dword_7F950[a1[1]], dword_7FD50[a1[2]], dword_80150[a1[3]]] a2_1_box = [dword_7F550[a2[0]], dword_7F950[a2[1]], dword_7FD50[a2[2]], dword_80150[a2[3]]] a3_1_box = [dword_7F550[a3[0]], dword_7F950[a3[1]], dword_7FD50[a3[2]], dword_80150[a3[3]]] a4_1_box = [dword_7F550[a4[0]], dword_7F950[a4[1]], dword_7FD50[a4[2]], dword_80150[a4[3]]] if i == 0: # 矩阵运算 这块不太一样 d1 = [a4_1_box[0], a3_1_box[1], a2_1_box[2], a1_1_box[3]] d2 = [a3_1_box[0], a2_1_box[1], a1_1_box[2], a4_1_box[3]] d3 = [a2_1_box[0], a1_1_box[1], a4_1_box[2], a3_1_box[3]] d4 = [a1_1_box[0], a4_1_box[1], a3_1_box[2], a2_1_box[3]] else: # 矩阵运算 d1 = [a1_1_box[0], a2_1_box[1], a3_1_box[2], a4_1_box[3]] d2 = [a2_1_box[0], a3_1_box[1], a4_1_box[2], a1_1_box[3]] d3 = [a3_1_box[0], a4_1_box[1], a1_1_box[2], a2_1_box[3]] d4 = [a4_1_box[0], a1_1_box[1], a2_1_box[2], a3_1_box[3]] # 拼接 plaintext_block[0] = reduce(lambda x, y: x ^ y, d1) ^ keys[num] plaintext_block[1] = reduce(lambda x, y: x ^ y, d2) ^ keys[num + 1] plaintext_block[2] = reduce(lambda x, y: x ^ y, d3) ^ keys[num + 2] plaintext_block[3] = reduce(lambda x, y: x ^ y, d4) ^ keys[num + 3] # 后四位 a1 = self._split_int(plaintext_block[0]) # 这块是按顺序的 a2 = self._split_int(plaintext_block[1]) a3 = self._split_int(plaintext_block[2]) a4 = self._split_int(plaintext_block[3]) a1_sum_box = [SBoxIV[a4[0]], SBoxIV[a1[1]], SBoxIV[a2[2]], SBoxIV[a3[3]]] # 合并后 a2_sum_box = [SBoxIV[a3[0]], SBoxIV[a4[1]], SBoxIV[a1[2]], SBoxIV[a2[3]]] # 合并后 a3_sum_box = [SBoxIV[a2[0]], SBoxIV[a3[1]], SBoxIV[a4[2]], SBoxIV[a1[3]]] # 合并后 a4_sum_box = [SBoxIV[a1[0]], SBoxIV[a2[1]], SBoxIV[a3[2]], SBoxIV[a4[3]]] # 合并后 plaintext_block[0] = self._joint_int(a1_sum_box) ^ keys[-1] plaintext_block[1] = self._joint_int(a2_sum_box) ^ keys[-2] plaintext_block[2] = self._joint_int(a3_sum_box) ^ keys[-3] plaintext_block[3] = self._joint_int(a4_sum_box) ^ keys[-4] return plaintext_block def _generate_key(self, key: bytes) -> list: """密钥扩展""" Rcon = [0x12310000, 0x2000100, 0x4020000, 0x8020200, 0x10102000, 0x30020400, 0x40002000, 0x80002000, 0x1B002000, 0x36200200] # 轮常数 Nr, Nk = 10 + (self.aes_type - 128) // 32, self.aes_type // 32 # Nr:轮数,Nk:密钥长度 w = [0 for _ in range(4 * (Nr + 1))] # 轮密钥 p = [4052295985, 4278194467, 4043314006, 4045621392] # 额外处理 for i in range(Nk): # 初始化是对的 w[i] = int.from_bytes(key[4 * i:4 * i + 4], 'big') ^ p[i] # print(f"w{i} => {hex(w[i])}") for i in range(Nk, 4 * (Nr + 1)): temp = w[i - 1] # print("******************************") # print(f"开始", hex(temp), i % Nk) if i % Nk == 0: temp = self._split_int(temp) # 拆分成 4x8bit temp = [SBox[temp[1]], SBox[temp[2]], SBox[temp[3]], SBox[temp[0]]] # sbox 的轮数发生变化了 temp = self._joint_int(temp) ^ Rcon[i // Nk - 1] # 合并回 32bit elif Nk > 6 and i % Nk == 4: temp = self._split_int(temp) # 拆分成 4x8bit temp = [SBox[temp[0]], SBox[temp[1]], SBox[temp[2]], SBox[temp[3]]] temp = self._joint_int(temp) # 合并回 32bit w[i] = w[i - Nk] ^ temp w = self._sort_key(w) # 替换处理key return w @staticmethod def _split_int(n: int) -> list: """拆分 32bit 成 4x8bit""" return [(n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF] @staticmethod def _joint_int(b: list) -> int: """合并 4x8bit 成 32bit""" return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3] def get_key(deviceId, hmac_main): """ 外部获取 接口 :param deviceId: 设备id :param hmac_main: 存在于机器的 s.xml :return: """ key = deviceId[:16] plaintext = base64.b64decode(hmac_main.encode("utf-8")) A = AES(key.encode("utf-8")) result = A.encrypt(plaintext) return result if __name__ == '__main__': key = "2fe75062-a528-33" m = AES(key.encode("utf-8")) hmac_main = "cDdMxUWZy3e2szBCUB04rZMxTdf6tVKcpCIRrDQGa/NS8Agki6U5MGN6c6QCT3t6amTAYBbcDwFlPndCV3AfaerPd36GS9sdmTeKzBU45YsIBsGAdBXyy2GnkRlDaVCO" plaintext = base64.b64decode(hmac_main.encode("utf-8")) pp = m.encrypt(plaintext) print(get_key(key, hmac_main))