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

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): self.fixed_aes_key = "......3690......" self.fixed_iv = "......0405......" self.public_rsa_key_b64 = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIVwAZ2E+O7qVmGPrBrVFVfe93V1bkLrV9LTbEA0tqPLgZzg/BPYQs0j02LZZ......" self.private_rsa_key_b64 = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAjoS58XGU1pP+SEiJPxe9tjNiTE3orbr5I2fHtWp64p5Xsa14Yw5apqIaBNL6ot7B+FMCN7514vQhdFOs+kKvKQIDAQABAkB08eJmhc4dGYlRpPvB4uhQJu/lLxTb4g3niJQugDZf11aF2R7pBEl3zPDkXbw9KE+DbvIA5U0IkzRpZg46nIAFAiEAy1WTzlY3qxrr+ioeQneFMQW6rJQ6......" 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: cipher = PKCS1_v1_5.new(self.public_rsa_key) encrypted_data = cipher.encrypt(data.encode('utf-8')) return base64.b64encode(encrypted_data).decode('utf-8') except ValueError as e: 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)}") encrypted_data = base64.b64decode(encrypted_data_b64) print(f"✅ Base64解码完成,数据长度: {len(encrypted_data)} 字节") cipher = PKCS1_v1_5.new(self.private_rsa_key) 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) 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) 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}×tamp={timestamp}" key_bytes = encrypted_aes_key.encode('utf-8') 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: json_data = json.loads(user_input) json_str = json.dumps(json_data, ensure_ascii=False, separators=(',', ':')) print("✅ 输入数据验证成功") print(f"原始数据: {json_str}") encrypt_data = self.aes_encrypt(json_str) print(f"✅ AES加密完成, encryptData长度: {len(encrypt_data)}") encrypted_aes_key = self.rsa_encrypt(self.fixed_aes_key) print(f"✅ RSA加密AES密钥完成, aesKey: {encrypted_aes_key}") 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") sign = self.generate_hmac_signature(encrypted_aes_key, encrypt_data, nonce_str, timestamp) print(f"✅ HMAC签名生成完成: {sign}") 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) 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) 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) 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()
|