背景:某客户系统存在多种算法混合加密以及签名校验,记录分析过程。

Rsa公钥为st(已省略):
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIVwAZ2E+O7qVmGPrBrVFVfe93V1bkLrV9LTbEA0tqPLgZzg/BPYQs0j02LZZ……

RSA私钥为ct(已省略):
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAjoS58XGU1pP+SEiJPxe9tjNiTE3orbr5I2fHtWp64p5Xsa14Yw5apqIaBNL6ot7B+FMCN7514vQhdFOs+kKvKQIDAQABAkB08eJmhc4dGYlRpPvB4uhQJu/lLxTb4g3niJQugDZf11aF2R7pBEl3zPDkXbw9KE+DbvIA5U0IkzRpZg46nIAFAiEAy1WTzlY3qxrr+ioeQneFMQW6rJQ6……

AES的固定密钥和iv(已省略):
ut = "……3690……", lt = "……04050……"

分析:

AES固定key/iv加密明文得到密文:

RSA公钥加密固定的AES密钥得到aeskey:


签名校验是由aeskey和content和noncestr和timestamp拼接进行hmacsha256生成:

控制台打印输出:

这里可以发现hmac256的key是aeskey,也就是rsa公钥加密固定密钥的值:

这样就成功生成了签名

此时有了签名,以及时间戳和nonce(可直接还原生成),此时也有了密文以及aeskey,已可以发送请求包

得到返回包后:

用RSA私钥解密返回包的aeskey得到解密的aes的密钥:

得到解密的aes密钥后,再加上固定的iv,对返回包密文进行解密:

至此模拟还原整个加解密流程:

Python脚本(密钥部分已脱敏):

import json
import base64
import random
import string
import time
import sys
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import pad, unpad
import hashlib
import hmac

class CompleteCryptoHandler:
def __init__(self):
# 固定参数(从JavaScript代码中确认)
self.fixed_aes_key = "......3690......" # 固定的AES密钥
self.fixed_iv = "......0405......" # 固定的IV

# RSA密钥对(从JavaScript代码中提取)
self.public_rsa_key_b64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIVwAZ2E+O7qVmGPrBrVFVfe93V1bkLrV9LTbEA0tqPLgZzg/BPYQs0j02LZZ......"
self.private_rsa_key_b64 = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAjoS58XGU1pP+SEiJPxe9tjNiTE3orbr5I2fHtWp64p5Xsa14Yw5apqIaBNL6ot7B+FMCN7514vQhdFOs+kKvKQIDAQABAkB08eJmhc4dGYlRpPvB4uhQJu/lLxTb4g3niJQugDZf11aF2R7pBEl3zPDkXbw9KE+DbvIA5U0IkzRpZg46nIAFAiEAy1WTzlY3qxrr+ioeQneFMQW6rJQ6......"

# 加载RSA密钥
self.public_rsa_key = self._load_public_key()
self.private_rsa_key = self._load_private_key()

print("=" * 60)
print(f"固定RSA公钥: {self.public_rsa_key_b64}")
print(f"固定RSA私钥: {self.private_rsa_key_b64}")
print(f"固定AES密钥: {self.fixed_aes_key}")
print(f"固定IV: {self.fixed_iv}")
print("AES填充模式: CBC/PKCS7")
print("RSA填充模式: PKCS1_v1_5")
print("=" * 60)

def _load_public_key(self):
"""加载RSA公钥"""
public_key_der = base64.b64decode(self.public_rsa_key_b64)
return RSA.import_key(public_key_der)

def _load_private_key(self):
"""加载RSA私钥"""
private_key_der = base64.b64decode(self.private_rsa_key_b64)
return RSA.import_key(private_key_der)

def generate_random_str(self, length=32):
"""生成随机字符串"""
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(length))

def rsa_encrypt(self, data):
"""RSA加密 - 使用PKCS1_v1_5填充模式"""
try:
# 创建PKCS1_v1_5加密器
cipher = PKCS1_v1_5.new(self.public_rsa_key)

# 加密数据
encrypted_data = cipher.encrypt(data.encode('utf-8'))

# Base64编码后返回
return base64.b64encode(encrypted_data).decode('utf-8')

except ValueError as e:
# PKCS1_v1_5对数据长度有限制,需要小于密钥长度-11字节
raise ValueError(f"RSA加密失败: {e}. 数据长度可能超过限制")

def rsa_decrypt(self, encrypted_data_b64):
"""RSA解密 - 使用PKCS1_v1_5填充模式"""
try:
print("🔓 开始RSA解密流程 (PKCS1_v1_5)")
print(f"📥 输入Base64编码数据长度: {len(encrypted_data_b64)}")

# 第一步:先进行Base64解码
encrypted_data = base64.b64decode(encrypted_data_b64)
print(f"✅ Base64解码完成,数据长度: {len(encrypted_data)} 字节")

# 第二步:创建PKCS1_v1_5解密器
cipher = PKCS1_v1_5.new(self.private_rsa_key)

# 第三步:进行RSA解密
decrypted_data = cipher.decrypt(encrypted_data, None)

if decrypted_data is None:
raise ValueError("RSA解密失败: 可能是密钥不匹配或数据损坏")

print("✅ RSA解密完成")
return decrypted_data.decode('utf-8')

except base64.binascii.Error as e:
raise ValueError(f"Base64解码失败: {e}")
except ValueError as e:
raise ValueError(f"RSA解密失败: {e}")
except Exception as e:
raise ValueError(f"解密过程中出错: {e}")

def aes_encrypt(self, plaintext):
"""AES加密 - CBC模式,PKCS7填充"""
key_bytes = self.fixed_aes_key.encode('utf-8')
iv_bytes = self.fixed_iv.encode('utf-8')
plaintext_bytes = plaintext.encode('utf-8')

# 填充数据
plaintext_bytes = pad(plaintext_bytes, AES.block_size)

# AES-CBC加密
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
encrypted_data = cipher.encrypt(plaintext_bytes)

return encrypted_data.hex().upper()

def aes_decrypt(self, encrypted_data_hex, aes_key):
"""AES解密 - CBC模式,PKCS7填充"""
key_bytes = aes_key.encode('utf-8')
iv_bytes = self.fixed_iv.encode('utf-8')
encrypted_data = bytes.fromhex(encrypted_data_hex)

# AES-CBC解密
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
decrypted_data = cipher.decrypt(encrypted_data)

# 去除填充
unpadded_data = unpad(decrypted_data, AES.block_size)
return unpadded_data.decode('utf-8')

def generate_hmac_signature(self, encrypted_aes_key, encrypt_data, nonce_str, timestamp):
"""生成HMAC-SHA256签名"""
param_str = f"aesKey={encrypted_aes_key}&content={encrypt_data}&nonceStr={nonce_str}&timestamp={timestamp}"
key_bytes = encrypted_aes_key.encode('utf-8')
# 使用HMAC-SHA256生成签名
signature = hmac.new(
key_bytes, # 密钥字节
param_str.encode('utf-8'), # 消息字节
digestmod=hashlib.sha256 # 算法
).hexdigest().upper() # 转为大写十六进制

print(f"🔍 密钥长度(bytes): {len(key_bytes)}")
print(f"✅ HMAC签名生成完成: {signature}")

return signature

def encrypt_request(self, user_input):
"""加密请求数据 - 完整流程"""
try:
# 1. 验证输入JSON
json_data = json.loads(user_input)
json_str = json.dumps(json_data, ensure_ascii=False, separators=(',', ':'))

print("✅ 输入数据验证成功")
print(f"原始数据: {json_str}")

# 2. 使用固定AES密钥加密数据
encrypt_data = self.aes_encrypt(json_str)
print(f"✅ AES加密完成, encryptData长度: {len(encrypt_data)}")

# 3. 使用RSA公钥加密固定AES密钥 (PKCS1_v1_5模式)
encrypted_aes_key = self.rsa_encrypt(self.fixed_aes_key)
print(f"✅ RSA加密AES密钥完成, aesKey: {encrypted_aes_key}")

# 4. 生成其他参数
nonce_str = self.generate_random_str(32)
timestamp = int(time.time() * 1000)
encrypt_type = "AES"
sign_type = "SHA256"

print(f"📋 生成参数:")
print(f" nonceStr: {nonce_str}")
print(f" timestamp: {timestamp}")
print(f" RSA填充模式: PKCS1_v1_5")

# 5. 生成HMAC-SHA256签名
sign = self.generate_hmac_signature(encrypted_aes_key, encrypt_data, nonce_str, timestamp)
print(f"✅ HMAC签名生成完成: {sign}")

# 6. 构建完整请求包
encrypted_request = {
"sign": sign,
"signType": sign_type,
"aesKey": encrypted_aes_key,
"nonceStr": nonce_str,
"timestamp": timestamp,
"encryptType": encrypt_type,
"encryptData": encrypt_data
}

return encrypted_request

except json.JSONDecodeError:
raise ValueError("输入的不是有效JSON格式")
except Exception as e:
raise ValueError(f"加密过程中出错: {str(e)}")

def decrypt_response(self, encrypt_data, encrypted_aes_key):
"""解密响应数据 - 添加详细的解密过程显示"""
try:
print("🔓 开始解密响应数据 (PKCS1_v1_5模式)")
print("=" * 50)
print(f"📥 输入参数:")
print(f" encryptData长度: {len(encrypt_data)}")
print(f" encrypted_aes_key长度: {len(encrypted_aes_key)}")
print(f" encrypted_aes_key: {encrypted_aes_key}")
print("=" * 50)

# 1. RSA解密得到AES密钥 (PKCS1_v1_5模式)
print("\n🔑 RSA解密AES密钥过程 (PKCS1_v1_5):")
print(f" 输入encrypted_aes_key: {encrypted_aes_key}")

decrypted_aes_key = self.rsa_decrypt(encrypted_aes_key)

print(f"✅ RSA解密AES密钥完成!")
print(f"🔑 解密得到的真实AES密钥: [{decrypted_aes_key}]")
print(f"🔑 密钥长度: {len(decrypted_aes_key)} 字符")
print(f"🔑 密钥HEX表示: {decrypted_aes_key.encode('utf-8').hex().upper()}")
print("=" * 50)

# 2. 使用解密得到的AES密钥解密数据
print("\n📄 AES解密数据过程:")
print(f" 输入encrypt_data长度: {len(encrypt_data)}")
print(f" 使用的IV: {self.fixed_iv}")
print(f" 使用的AES密钥: {decrypted_aes_key}")

decrypted_data_str = self.aes_decrypt(encrypt_data, decrypted_aes_key)

print(f"✅ AES解密完成!")
print(f"📄 解密后的原始数据: {decrypted_data_str}")
print("=" * 50)

# 3. 解析JSON数据
print("\n🔍 解析JSON数据:")
decrypted_data = json.loads(decrypted_data_str)
print(f"✅ JSON解析成功!")

return decrypted_data

except Exception as e:
raise ValueError(f"解密过程中出错: {str(e)}")


def main():
"""主函数 - 提供交互式加解密工具"""
crypto = CompleteCryptoHandler()

print("=" * 60)
print("基于AES-CBC + RSA(PKCS1_v1_5) + HMAC-SHA256的加解密工具")
print("=" * 60)

while True:
try:
print("\n请选择操作:")
print("1. 加密JSON数据(生成请求包)")
print("2. 解密密文数据(解密响应包)")
print("q. 退出")

choice = input("\n请输入选择 (1/2/q): ").strip().lower()

if choice == 'q':
print("程序已退出")
break

elif choice == '1':
print("\n【加密模式 - 生成请求包】")
print("示例: {\"configType\":\"mobile\",\"encrypt\":true}")
user_input = input("请输入要加密的JSON数据: ").strip()

if not user_input:
print("错误: 输入不能为空")
continue

try:
result = crypto.encrypt_request(user_input)
print("\n" + "=" * 40)
print("✅ 加密成功 - 请求包格式:")
print("=" * 40)
print(json.dumps(result, indent=2, ensure_ascii=False))

except Exception as e:
print(f"❌ 加密错误: {e}")

elif choice == '2':
print("\n【解密模式 - 解密响应包】")
encrypt_data = input("请输入encryptData: ").strip()
aes_key = input("请输入aesKey: ").strip()
if not encrypt_data or not aes_key:
print("错误: 参数不能为空")
continue

try:
result = crypto.decrypt_response(encrypt_data, aes_key)
print("\n" + "=" * 40)
print("✅ 解密成功:")
print("=" * 40)
if isinstance(result, dict):
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(result)
except Exception as e:
print(f"❌ 解密错误: {e}")
else:
print("错误: 请输入1、2或q")

except KeyboardInterrupt:
print("\n程序被用户中断")
break
except Exception as e:
print(f"发生未知错误: {e}")


if __name__ == "__main__":
main()