算法暴露接口(xhs、dy、ks、wx、hnw)
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.

199 lines
7.8 KiB

7 months ago
  1. from functools import reduce
  2. import base64
  3. from xhs.shield_const import *
  4. """
  5. hmac_main aes处理
  6. aes
  7. 6.97.0.1
  8. """
  9. class AES:
  10. def __init__(self, key: bytes):
  11. self.aes_type = len(key) * 8
  12. self._key_r = self._generate_key(key)
  13. def _sort_key(self, w_list):
  14. """
  15. key
  16. """
  17. def change_char(w):
  18. w_4 = self._split_int(w) # 拆分成 4x8bit
  19. s_w_4 = [SBox[w_4[0]], SBox[w_4[1]], SBox[w_4[2]], SBox[w_4[3]]]
  20. 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]]]
  21. key4 = reduce(lambda x, y: x ^ y, s_s_w_4)
  22. return key4
  23. # 交换位置
  24. for i in range(len(w_list) // 2):
  25. tmp = w_list[i]
  26. if i > 3: # 需要交换位置
  27. tmp = change_char(tmp)
  28. w_list[len(w_list) - i - 1] = change_char(w_list[len(w_list) - i -1])
  29. w_list[i] = w_list[len(w_list) - i -1]
  30. w_list[len(w_list) - i -1] = tmp
  31. # print(i, len(w_list) - i -1)
  32. return w_list
  33. @staticmethod
  34. def hex_string(num, step=2):
  35. """
  36. step
  37. """
  38. tmp_string = hex(num)[2:]
  39. if len(tmp_string) < step:
  40. tmp_string = '0' * (step - len(tmp_string)) + tmp_string
  41. return tmp_string
  42. def encrypt(self, plaintext:bytes):
  43. """
  44. :param plaintext:
  45. :return:
  46. """
  47. state = [[plaintext[i + j] for j in range(16)] for i in range(0, len(plaintext), 16)] # 先分组
  48. result = []
  49. # 进行加密流程
  50. for p in range(len(state)):
  51. _plaintext_block = [self._joint_int(state[p][i:i+4]) for i in range(0, 16, 4)]
  52. state[p] = _plaintext_block.copy() # 合并为每四个字节的数组
  53. _encrypt_block = self.encrypt_block(_plaintext_block) # 处理第一块
  54. if p > 0:
  55. extra_block = [self.hex_string(_encrypt_block[i] ^ state[p - 1][i], 8) for i in range(4)] # 异或处理
  56. result.append("".join(extra_block))
  57. return "".join(result[:4])
  58. def encrypt_block(self, plaintext_block):
  59. """
  60. """
  61. keys = self._key_r
  62. # 第一轮由于明文和那个key是反的 单独计算
  63. plaintext_block[0] = plaintext_block[0] ^ keys[3]
  64. plaintext_block[1] = plaintext_block[1] ^ keys[2]
  65. plaintext_block[2] = plaintext_block[2] ^ keys[1]
  66. plaintext_block[3] = plaintext_block[3] ^ keys[0]
  67. for i in range(0, 9):
  68. num = (i + 1) * 4
  69. a1 = self._split_int(plaintext_block[0]) # 这块是按顺序的
  70. a2 = self._split_int(plaintext_block[1])
  71. a3 = self._split_int(plaintext_block[2])
  72. a4 = self._split_int(plaintext_block[3])
  73. # 查表法进行替换
  74. a1_1_box = [dword_7F550[a1[0]], dword_7F950[a1[1]], dword_7FD50[a1[2]], dword_80150[a1[3]]]
  75. a2_1_box = [dword_7F550[a2[0]], dword_7F950[a2[1]], dword_7FD50[a2[2]], dword_80150[a2[3]]]
  76. a3_1_box = [dword_7F550[a3[0]], dword_7F950[a3[1]], dword_7FD50[a3[2]], dword_80150[a3[3]]]
  77. a4_1_box = [dword_7F550[a4[0]], dword_7F950[a4[1]], dword_7FD50[a4[2]], dword_80150[a4[3]]]
  78. if i == 0:
  79. # 矩阵运算 这块不太一样
  80. d1 = [a4_1_box[0], a3_1_box[1], a2_1_box[2], a1_1_box[3]]
  81. d2 = [a3_1_box[0], a2_1_box[1], a1_1_box[2], a4_1_box[3]]
  82. d3 = [a2_1_box[0], a1_1_box[1], a4_1_box[2], a3_1_box[3]]
  83. d4 = [a1_1_box[0], a4_1_box[1], a3_1_box[2], a2_1_box[3]]
  84. else:
  85. # 矩阵运算
  86. d1 = [a1_1_box[0], a2_1_box[1], a3_1_box[2], a4_1_box[3]]
  87. d2 = [a2_1_box[0], a3_1_box[1], a4_1_box[2], a1_1_box[3]]
  88. d3 = [a3_1_box[0], a4_1_box[1], a1_1_box[2], a2_1_box[3]]
  89. d4 = [a4_1_box[0], a1_1_box[1], a2_1_box[2], a3_1_box[3]]
  90. # 拼接
  91. plaintext_block[0] = reduce(lambda x, y: x ^ y, d1) ^ keys[num]
  92. plaintext_block[1] = reduce(lambda x, y: x ^ y, d2) ^ keys[num + 1]
  93. plaintext_block[2] = reduce(lambda x, y: x ^ y, d3) ^ keys[num + 2]
  94. plaintext_block[3] = reduce(lambda x, y: x ^ y, d4) ^ keys[num + 3]
  95. # 后四位
  96. a1 = self._split_int(plaintext_block[0]) # 这块是按顺序的
  97. a2 = self._split_int(plaintext_block[1])
  98. a3 = self._split_int(plaintext_block[2])
  99. a4 = self._split_int(plaintext_block[3])
  100. a1_sum_box = [SBoxIV[a4[0]], SBoxIV[a1[1]], SBoxIV[a2[2]], SBoxIV[a3[3]]] # 合并后
  101. a2_sum_box = [SBoxIV[a3[0]], SBoxIV[a4[1]], SBoxIV[a1[2]], SBoxIV[a2[3]]] # 合并后
  102. a3_sum_box = [SBoxIV[a2[0]], SBoxIV[a3[1]], SBoxIV[a4[2]], SBoxIV[a1[3]]] # 合并后
  103. a4_sum_box = [SBoxIV[a1[0]], SBoxIV[a2[1]], SBoxIV[a3[2]], SBoxIV[a4[3]]] # 合并后
  104. plaintext_block[0] = self._joint_int(a1_sum_box) ^ keys[-1]
  105. plaintext_block[1] = self._joint_int(a2_sum_box) ^ keys[-2]
  106. plaintext_block[2] = self._joint_int(a3_sum_box) ^ keys[-3]
  107. plaintext_block[3] = self._joint_int(a4_sum_box) ^ keys[-4]
  108. return plaintext_block
  109. def _generate_key(self, key: bytes) -> list:
  110. """密钥扩展"""
  111. Rcon = [0x12310000, 0x2000100, 0x4020000, 0x8020200, 0x10102000, 0x30020400, 0x40002000, 0x80002000, 0x1B002000, 0x36200200] # 轮常数
  112. Nr, Nk = 10 + (self.aes_type - 128) // 32, self.aes_type // 32 # Nr:轮数,Nk:密钥长度
  113. w = [0 for _ in range(4 * (Nr + 1))] # 轮密钥
  114. p = [4052295985, 4278194467, 4043314006, 4045621392] # 额外处理
  115. for i in range(Nk): # 初始化是对的
  116. w[i] = int.from_bytes(key[4 * i:4 * i + 4], 'big') ^ p[i]
  117. # print(f"w{i} => {hex(w[i])}")
  118. for i in range(Nk, 4 * (Nr + 1)):
  119. temp = w[i - 1]
  120. # print("******************************")
  121. # print(f"开始", hex(temp), i % Nk)
  122. if i % Nk == 0:
  123. temp = self._split_int(temp) # 拆分成 4x8bit
  124. temp = [SBox[temp[1]], SBox[temp[2]], SBox[temp[3]], SBox[temp[0]]] # sbox 的轮数发生变化了
  125. temp = self._joint_int(temp) ^ Rcon[i // Nk - 1] # 合并回 32bit
  126. elif Nk > 6 and i % Nk == 4:
  127. temp = self._split_int(temp) # 拆分成 4x8bit
  128. temp = [SBox[temp[0]], SBox[temp[1]],
  129. SBox[temp[2]], SBox[temp[3]]]
  130. temp = self._joint_int(temp) # 合并回 32bit
  131. w[i] = w[i - Nk] ^ temp
  132. w = self._sort_key(w) # 替换处理key
  133. return w
  134. @staticmethod
  135. def _split_int(n: int) -> list:
  136. """拆分 32bit 成 4x8bit"""
  137. return [(n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF]
  138. @staticmethod
  139. def _joint_int(b: list) -> int:
  140. """合并 4x8bit 成 32bit"""
  141. return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]
  142. def get_key(deviceId, hmac_main):
  143. """
  144. :param deviceId: id
  145. :param hmac_main: s.xml
  146. :return:
  147. """
  148. key = deviceId[:16]
  149. plaintext = base64.b64decode(hmac_main.encode("utf-8"))
  150. A = AES(key.encode("utf-8"))
  151. result = A.encrypt(plaintext)
  152. return result
  153. if __name__ == '__main__':
  154. key = "2fe75062-a528-33"
  155. m = AES(key.encode("utf-8"))
  156. hmac_main = "cDdMxUWZy3e2szBCUB04rZMxTdf6tVKcpCIRrDQGa/NS8Agki6U5MGN6c6QCT3t6amTAYBbcDwFlPndCV3AfaerPd36GS9sdmTeKzBU45YsIBsGAdBXyy2GnkRlDaVCO"
  157. plaintext = base64.b64decode(hmac_main.encode("utf-8"))
  158. pp = m.encrypt(plaintext)
  159. print(get_key(key, hmac_main))