encrypt.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. """
  2. RSA+AES混合加密工具
  3. """
  4. import base64
  5. import json
  6. from typing import Dict, Any, Optional
  7. from cryptography.hazmat.primitives import serialization
  8. from cryptography.hazmat.primitives.asymmetric import rsa, padding
  9. from cryptography.hazmat.primitives import hashes
  10. from cryptography.hazmat.backends import default_backend
  11. from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
  12. from cryptography.hazmat.primitives.padding import PKCS7
  13. from app.config import settings
  14. from app.core.logger import logger
  15. class RSAEncryptor:
  16. """RSA+AES混合加密器"""
  17. def __init__(self):
  18. self.private_key: Optional[rsa.RSAPrivateKey] = None
  19. self.public_key: Optional[rsa.RSAPublicKey] = None
  20. def generate_key_pair(self) -> tuple[str, str]:
  21. """生成密钥对"""
  22. private_key = rsa.generate_private_key(
  23. public_exponent=65537,
  24. key_size=2048,
  25. backend=default_backend()
  26. )
  27. public_key = private_key.public_key()
  28. # 序列化为PEM格式
  29. private_pem = private_key.private_bytes(
  30. encoding=serialization.Encoding.PEM,
  31. format=serialization.PrivateFormat.PKCS8,
  32. encryption_algorithm=serialization.NoEncryption()
  33. ).decode('utf-8')
  34. public_pem = public_key.public_bytes(
  35. encoding=serialization.Encoding.PEM,
  36. format=serialization.PublicFormat.SubjectPublicKeyInfo
  37. ).decode('utf-8')
  38. return private_pem, public_pem
  39. def load_private_key(self, private_key_pem: str):
  40. """加载私钥"""
  41. try:
  42. self.private_key = serialization.load_pem_private_key(
  43. private_key_pem.encode(),
  44. password=None,
  45. backend=default_backend()
  46. )
  47. self.public_key = self.private_key.public_key()
  48. logger.info("私钥加载成功")
  49. except Exception as e:
  50. logger.error(f"私钥加载失败: {e}")
  51. raise
  52. def decrypt(self, encrypted_data: str) -> Dict[str, Any]:
  53. """解密数据(支持RSA+AES混合加密和纯RSA加密)"""
  54. if not settings.ENCRYPT_ENABLED:
  55. return json.loads(encrypted_data)
  56. if not self.private_key:
  57. raise ValueError("私钥未加载")
  58. try:
  59. # Base64解码
  60. encrypted_bytes = base64.b64decode(encrypted_data)
  61. # 判断是混合加密还是纯RSA加密
  62. # 混合加密:加密的AES密钥(256字节) + IV(16字节) + 加密的数据
  63. # 纯RSA加密:直接是RSA加密的数据(通常小于256字节)
  64. # 如果数据长度大于256字节,认为是混合加密
  65. if len(encrypted_bytes) > 256:
  66. # 混合加密模式
  67. # 提取加密的AES密钥(前256字节)
  68. encrypted_aes_key = encrypted_bytes[:256]
  69. # 提取IV(接下来16字节)
  70. iv = encrypted_bytes[256:272]
  71. # 提取加密的数据(剩余部分)
  72. encrypted_payload = encrypted_bytes[272:]
  73. # 使用RSA解密AES密钥
  74. aes_key = self.private_key.decrypt(
  75. encrypted_aes_key,
  76. padding.OAEP(
  77. mgf=padding.MGF1(algorithm=hashes.SHA256()),
  78. algorithm=hashes.SHA256(),
  79. label=None
  80. )
  81. )
  82. # 使用AES解密数据
  83. cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
  84. decryptor = cipher.decryptor()
  85. padded_data = decryptor.update(encrypted_payload) + decryptor.finalize()
  86. # 去除PKCS7填充
  87. unpadder = PKCS7(128).unpadder()
  88. decrypted_bytes = unpadder.update(padded_data) + unpadder.finalize()
  89. # JSON解析
  90. return json.loads(decrypted_bytes.decode('utf-8'))
  91. else:
  92. # 纯RSA加密模式(向后兼容)
  93. decrypted = self.private_key.decrypt(
  94. encrypted_bytes,
  95. padding.OAEP(
  96. mgf=padding.MGF1(algorithm=hashes.SHA256()),
  97. algorithm=hashes.SHA256(),
  98. label=None
  99. )
  100. )
  101. # JSON解析
  102. return json.loads(decrypted.decode('utf-8'))
  103. except Exception as e:
  104. logger.error(f"数据解密失败: {e}")
  105. raise
  106. # 全局加密器实例
  107. encryptor = RSAEncryptor()