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.
200 lines
7.8 KiB
200 lines
7.8 KiB
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))
|