| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- # -*- coding: utf-8 -*-
- # Author : Charley
- # Python : 3.10.8
- # Date : 2025/8/26 14:31
- from Crypto.Cipher import AES
- from Crypto.Util.Padding import pad, unpad
- import json
- import base64
- import hashlib
- import time
- import random
- import execjs
- from loguru import logger
- # def _define_property(obj, key, value):
- # """
- # 模拟JavaScript中的_defineProperty函数
- # 相当于 Object.defineProperty(obj, key, {value: value, enumerable: true, configurable: true, writable: true})
- # 简单来说就是给对象添加一个可枚举的属性
- # """
- # # 在Python中,这相当于直接给字典添加键值对
- # result = {}
- # if isinstance(obj, dict):
- # result.update(obj)
- # result[key] = value
- # return result
- #
- #
- # def process_encrypted_params(params, method="POST", encryption_enable=True):
- # """
- # 处理加密参数,模拟JavaScript中的逻辑
- #
- # P = s.default.aesEncrypt(A),
- # E = this.encryptionEnable ? "{}" == A ? {} : n({}, "GET" == o ? "encryptionUrlParams" : "encryptionBodyParams", "GET" == o ? encodeURIComponent(P) : P) : i,
- # """
- # if not encryption_enable:
- # return params
- #
- # # 将参数转换为JSON字符串 (A)
- # if isinstance(params, dict) and not params: # 空字典
- # A = "{}"
- # elif params is None:
- # A = "{}"
- # else:
- # A = json.dumps(params, separators=(',', ':'), ensure_ascii=False)
- #
- # # 如果是空对象,返回空字典
- # if A == "{}":
- # return {}
- #
- # # 进行AES加密得到 P
- # P = pokemon_aes_encrypt(A)
- #
- # # 根据HTTP方法确定参数名和是否URL编码
- # if method.upper() == "GET":
- # param_name = "encryptionUrlParams"
- # param_value = quote(P, safe='') if P else P
- #
- # else:
- # param_name = "encryptionBodyParams"
- # param_value = P
- #
- # # 使用_define_property创建最终对象 E
- # E = _define_property({}, param_name, param_value)
- #
- # return E
- class PokemonAESUtil:
- """宝可梦卡牌数据AES加解密工具类"""
- def __init__(self):
- # 固定的密钥字符串
- KEY_STRING = "Njda*7^%1<.)0=+u&%hkfs;k"
- # 将密钥字符串转换为字节
- self.key_bytes = KEY_STRING.encode('utf-8')
- # CryptoJS 在 keySize 未明确指定或不标准时,会使用密钥字节的前 16/24/32 字节
- # 由于密钥是 24 字节,使用 AES-192 (24 字节密钥)
- if len(self.key_bytes) < 24:
- # 用 null 字节填充到 24 字节
- self.key_bytes = self.key_bytes.ljust(24, b'\0')
- elif len(self.key_bytes) > 24:
- # 截取前 24 字节
- self.key_bytes = self.key_bytes[:24]
- def encrypt(self, data):
- """
- AES ECB 模式加密,PKCS7 填充
- :param data: 要加密的数据 (字典或字符串)
- :return: Base64 编码的密文字符串
- """
- # 创建 AES ECB 模式加密器
- cipher = AES.new(self.key_bytes, AES.MODE_ECB)
- # 处理输入数据
- if isinstance(data, dict):
- # 如果是字典,转换为紧凑格式的JSON字符串
- plaintext = json.dumps(data, separators=(',', ':'))
- else:
- # 如果是字符串,直接使用
- plaintext = str(data)
- # 将明文字符串编码为 UTF-8 字节
- plaintext_bytes = plaintext.encode('utf-8')
- # 使用 PKCS7 填充
- padded_plaintext = pad(plaintext_bytes, AES.block_size)
- # 执行加密
- ciphertext_bytes = cipher.encrypt(padded_plaintext)
- # 将密文字节进行 Base64 编码并转换为字符串
- ciphertext_b64 = base64.b64encode(ciphertext_bytes).decode('utf-8')
- return ciphertext_b64
- def decrypt(self, ciphertext_b64):
- """
- AES ECB 模式解密,PKCS7 去填充
- :param ciphertext_b64: Base64 编码的密文字符串
- :return: 解密后的原始对象 (通常是字典)
- """
- # 创建 AES ECB 模式解密器
- cipher = AES.new(self.key_bytes, AES.MODE_ECB)
- # 将 Base64 字符串解码为字节
- ciphertext_bytes = base64.b64decode(ciphertext_b64)
- # 执行解密
- padded_plaintext_bytes = cipher.decrypt(ciphertext_bytes)
- # 移除 PKCS7 填充
- plaintext_bytes = unpad(padded_plaintext_bytes, AES.block_size)
- # 将字节解码为 UTF-8 字符串
- plaintext = plaintext_bytes.decode('utf-8')
- # 尝试解析 JSON 字符串为 Python 对象,如果失败则返回原始字符串
- try:
- return json.loads(plaintext)
- except json.JSONDecodeError:
- return plaintext
- # 创建全局实例,方便直接调用
- aes_util = PokemonAESUtil()
- # 便捷函数,可以直接调用
- def pokemon_aes_encrypt(data):
- """
- 便捷加密函数
- :param data: 要加密的数据 (字典或字符串)
- :return: Base64 编码的密文字符串
- """
- return aes_util.encrypt(data)
- def pokemon_aes_decrypt(ciphertext_b64):
- """
- 便捷解密函数
- :param ciphertext_b64: Base64 编码的密文字符串
- :return: 解密后的原始对象
- """
- return aes_util.decrypt(ciphertext_b64)
- """
- function n(e, r, t) {
- var n = new Array
- , a = 0;
- for (var i in e)
- n[a] = i,
- a++;
- var o = n.sort()
- , u = {};
- for (var s in o)
- u[o[s]] = e[o[s]];
- if (Array.isArray(e)) {
- if (r)
- return JSON.parse(JSON.stringify(e));
- u = {
- str: JSON.stringify(e)
- }
- }
- return JSON.parse(JSON.stringify(u, (function(e, r) {
- if (e) {
- if (null == r || null == r)
- return;
- return r instanceof Object ? t ? r : JSON.stringify(r) : "" + r
- }
- return r
- }
- )))
- }
- """
- def n(params, is_secret, encryption_enable):
- """
- 模拟JavaScript中的n函数
- 参数说明:
- params: 要处理的参数对象 (对应JavaScript中的e)
- is_secret: 是否为secret处理 (对应JavaScript中的r)
- encryption_enable: 是否启用加密 (对应JavaScript中的t)
- JavaScript源码分析:
- 1. 对对象的键进行排序
- 2. 如果是数组,根据is_secret决定处理方式
- 3. 使用自定义序列化函数处理所有值
- """
- # 如果params是None,直接返回
- if params is None:
- return params
- # 初始化变量(模拟JavaScript变量声明)
- keys_array = []
- index = 0
- # 模拟 for (var i in e) 循环,提取所有键
- # 注意:对于数组,键是索引(0, 1, 2, ...)
- if isinstance(params, (dict, list)):
- if isinstance(params, dict):
- # 对于字典,提取键
- for key in params:
- keys_array.append(key)
- index += 1
- else:
- # 对于数组,提取索引作为键
- for i in range(len(params)):
- keys_array.append(str(i))
- index += 1
- # 排序键
- sorted_keys = sorted(keys_array)
- # 创建新对象 u,按键的排序顺序重建
- u = {}
- if isinstance(params, dict):
- for key in sorted_keys:
- u[key] = params[key]
- elif isinstance(params, list):
- for key in sorted_keys:
- # key是字符串索引,需要转为整数
- idx = int(key)
- u[key] = params[idx]
- # 检查是否为数组
- if isinstance(params, list):
- if is_secret:
- return json.loads(json.dumps(params, separators=(',', ':')))
- else:
- u = {
- "str": json.dumps(params, separators=(',', ':'))
- }
- # 自定义序列化函数(模拟JavaScript的replacer函数)
- def replacer(key_, value):
- # key为空字符串表示是根对象
- if key_ == "":
- return value
- # 如果值为None,返回None(在JavaScript中会跳过)
- if value is None:
- return None
- # 如果值是对象(字典或列表)
- if isinstance(value, (dict, list)):
- if encryption_enable:
- return value # 保持原对象
- else:
- return json.dumps(value, separators=(',', ':')) # 转为JSON字符串,不带空格
- else:
- # 其他类型转为字符串
- return str(value)
- # 递归应用replacer函数
- def apply_replacer(obj, parent_key=""):
- if isinstance(obj, dict):
- result = {}
- for k, v in obj.items():
- processed_value = replacer(k, v)
- if processed_value is not None: # 跳过None值
- if isinstance(processed_value, dict):
- result[k] = apply_replacer(processed_value, k)
- elif isinstance(processed_value, list):
- # 对于列表,需要特殊处理
- list_result = []
- for ii, item in enumerate(processed_value):
- if isinstance(item, (dict, list)):
- list_result.append(apply_replacer(item, str(ii)))
- else:
- list_result.append(replacer(str(ii), item))
- result[k] = list_result
- else:
- result[k] = processed_value
- return result
- else:
- return obj
- # 应用replacer处理
- if isinstance(params, list) and not is_secret:
- # 对于数组且非secret情况,u已经是{"str": "..."}格式
- processed_obj = u
- else:
- processed_obj = apply_replacer(u)
- # 最后进行JSON序列化再反序列化,使用紧凑格式(无空格)
- return json.loads(json.dumps(processed_obj, separators=(',', ':')))
- def api_sign(timeout, user_token, params, encryption_enable=True, need_md5=False):
- """
- 对应JavaScript中的apiSign函数
- JavaScript代码分析:
- signature: (0,
- e.default)("".concat(a).concat(f).concat(s).concat(u).concat("fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb")).toString().toLowerCase()
- 参数对应:
- a = user_token
- f = JSON.stringify(n(params, false, encryption_enable))
- s = nonce
- u = timestamp
- e.default = MD5函数
- """
- # 计算timestamp: 当前时间加上timeout
- current_time = int(time.time() * 1000) # JavaScript中Date.parse返回毫秒
- timestamp = str(current_time + timeout)
- # timestamp = "1756448767584"
- # 生成随机nonce (6位随机数)
- # nonce = random.randint(100000, 999999)
- nonce = round(1e6 * random.random())
- # nonce = 912471
- # params = json.dumps(params, separators=(',', ':'))
- # 处理参数
- # 用于签名字符串计算
- f = json.dumps(n(params, False, encryption_enable), separators=(',', ':'), ensure_ascii=False)
- # f = json.dumps(n(params, False, encryption_enable), separators=(',', ':'))
- logger.info(f"f值:{f}")
- # print('f_type:',type(f))
- # 用于secretJsonParams
- d = json.dumps(n(params, True, encryption_enable), separators=(',', ':'), ensure_ascii=False)
- # 拼接签名字符串
- signature_string = f"{user_token}{f}{nonce}{timestamp}fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb"
- # print("签名字符串:", signature_string)
- # print("签名字符串:", type(signature_string))
- logger.info(f"待 MD5签名 字符串:{signature_string}")
- # signature_string = '{"code":"151C3"}9991231756196851221fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb'
- if need_md5:
- # 读取JavaScript文件内容
- with open('md5_encrypt.js', 'r', encoding='utf-8') as f:
- js_code = f.read()
- # 编译JavaScript代码
- ctx = execjs.compile(js_code)
- # 调用r函数
- # test_string = '{"banCardFlag":"0","commodityIds":"279","commoditySelectedList":[{"id":"279","commodityName":"收集啦151 惊","commodityCode":"151C3","salesDate":"2025-07-18"}],"pageNum":"8","pageSize":"50"}9124711756448767584fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb'
- signature = ctx.call('r', signature_string)
- # print(f"JavaScript MD5结果: {signature}")
- else:
- # 计算MD5签名并转为小写 (对应JavaScript中的e.default)
- signature = hashlib.md5(signature_string.encode('utf-8')).hexdigest().lower()
- return {
- "timestamp": timestamp,
- "nonce": nonce,
- "signature": signature,
- "secretJsonParams": d
- }
- # --- 使用示例 ---
- if __name__ == "__main__":
- # 参数加密后: "sWrJmSCVKNjxWn/WaVG9nv7UPCwAwlSvWkYqcX9N9aWXF5LMXegsN0edfLAq5FTTbY5QxpXn1uH/V00F6dSYib3Q9GjFHTbT7Cy7y3fF7frvzsjCW+3lVugoS46XCcUpODM8AhgQcaFrbWZeSDuZO79KGjiMDRmqk6KyCm9olBIU09f3KTGl95QKDSM36ksdgYzboOIb6gdktybRColS/LKk61Nnw/2NPCBNJE+EdXK2dvY5K3CIYomQt+MKamYBBdM4XoPRhAbyPATmSWUZAw=="
- # response加密后:
- # encrypted_11 = '1 Doxhb1drnjJaHMMC2uECUlgJKzHJrbOas+D7s4skML6PHHk1U+igtdDgZ4OwcpS4n/gOJnuJNkpKPK5ihkyjwoi70YfZHj5tpE0XtjVrVG1Svua1kULJHVOInLgXKm1iEjuwcfNsSvinVRADtuSalKTveIx1RuRcb5R3sGKLgd/VMlN21UaRZoJtOBpUFJy4kkI256GCP1G1Les3m0Z264bBs5o3Ux3VzhgdqbTISRZMmYGZsCObUzL310S9cnPi7FlX5U5VNUSGRMnn2YlkR1UkRl8wM2Jxfmjz4iUPwLErhD5Tn3c7hevw0fvQJTE9k28oEKxTr6cRoN0iDjsS2Fg9wxHj3lV4qdiDgOIkuTj4tniy53WwkmgnMN1FI9ibBHoTrqxMaNXkHaM50VgfQ6+c050n9QNIfO9mcvbGzBBDC6/Y800NPyXEUlyqLulMvDbpQ8NbWg9uH61qSbp4derg32cgawN0nJUSYR1Rk0bB6wV4jgc0eLQzxRQ/LXJlERhids9OvO/Ec0sKEv906MrEJ8j6OQ9vpgqwkw4H7hS4LVzD/NKIqxNDt5ZuMnFnIsjamvpRuPFL8t1xFsu1lAJ8yZyPpCAbGCqzPPt0IYYZVwsNmMGGjrhNKj268yO4vV48H5NGEveyYapDmY8Fd07HAEK6eDNFTIhd3JCgII91K85PqAPYHSO2b3Fnu/PNU/2 Nt9SJOo610Yu4e12O2WBoawzZk+LCPaOax8yqtJgtTJhXUTfwQKm087Lc9vyazpFO/qKewOMXnK1fe1nZUrtm1U93klK9AJQZkX/n55WmjZ3HC9JHzesFbnL+2 PGmaHWmuGxrg56+UyL/7 Lw4etJwPbz05E7ESiX67RvxY9nalBRcDDdzSYAiLb7OcyaRqge4nmD0g8RNWoWuzB5gtR0JkdR41zM9WD+uvzxt915l2+5 Q6GHyiSTPUnUxa76Vg3kGwjX+7 TRztcBdvDEnXNu/ZzbTprr74cgOJTrJ76YzjNkizkPGAn7GTPda3tkZPv4h9AHGtpn03UfE1u9DXHtfaaM9lJizd7b4umcAx91RQwaBvZIBVbqk5qHUQLnmDE0WMhusR1BJzWY7Ue5VdVwbPHRK+zgxACV66yIVjnT9iip8IfEVtU8wK7XTKSCn6OIGmO1QxOq3HE6m3iywTL4bASSX2+T+3 SgOqL8gPNt67foK52h4igfDqQwvNa0pL6/9 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'
- #
- # decrypted_data = aes_decrypt(encrypted_11)
- # 要加密的原始数据
- original_data = {
- "banCardFlag": "0",
- "commodityIds": "279",
- "commoditySelectedList": [
- {
- "id": "279",
- "commodityName": "收集啦151 惊",
- "commodityCode": "151C3",
- "salesDate": "2025-07-18"
- }
- ],
- "pageNum": "5",
- "pageSize": "50"
- }
- print("原始数据:", original_data)
- # # 方式1: 使用类实例
- # aes_tool = PokemonAESUtil()
- #
- # # 加密
- # encrypted = aes_tool.encrypt(original_data)
- # print("加密后 (Base64):", encrypted)
- #
- # # 解密
- # decrypted = aes_tool.decrypt(encrypted)
- # print("解密后:", decrypted)
- #
- # # 验证
- # assert original_data == decrypted, "加密/解密失败!"
- # print("方式1: 加密和解密成功,数据一致。")
- #
- # print("-" * 50)
- #
- # # 方式2: 使用便捷函数
- # encrypted2 = pokemon_aes_encrypt(original_data)
- # decrypted2 = pokemon_aes_decrypt(encrypted2)
- #
- # assert original_data == decrypted2, "加密/解密失败!"
- # print("方式2: 加密和解密成功,数据一致。")
- #
- # print("-" * 50)
- #
- # # 字符串加密示例
- # text_data = "Hello, Pokemon!"
- # encrypted_text = pokemon_aes_encrypt(text_data)
- # decrypted_text = pokemon_aes_decrypt(encrypted_text)
- #
- # assert text_data == decrypted_text, "字符串加密/解密失败!"
- # print(f"字符串加密解密示例: '{text_data}' -> '{decrypted_text}'")
- par = {"banCardFlag": "0", "commodityIds": "279", "commoditySelectedList": [
- {"id": "279", "commodityName": "收集啦151 惊", "commodityCode": "151C3", "salesDate": "2025-07-18"}],
- "pageNum": "8", "pageSize": "50"}
- # 浏览器结果:113530048412e1bfd9f69b6c39440908
- # 源码中的字符串:'{"banCardFlag":"0","commodityIds":"279","commoditySelectedList":[{"id":"279","commodityName":"收集啦151 惊","commodityCode":"151C3","salesDate":"2025-07-18"}],"pageNum":"8","pageSize":"50"}9124711756448767584fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb'
- # 代码中打印的: {"banCardFlag":"0","commodityIds":"279","commoditySelectedList":[{"id":"279","commodityName":"收集啦151 惊","commodityCode":"151C3","salesDate":"2025-07-18"}],"pageNum":"8","pageSize":"50"}9124711756448767584fWS21MVyxkYwEoCIAHieg7Tqn0jPl3GzQvRsDJcb
- sign_result = api_sign(
- timeout=584,
- user_token="",
- params=par
- )
- print(sign_result)
|