Files
aiagent/backend/app/services/encryption_service.py
2026-01-19 00:09:36 +08:00

133 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
加密服务
提供敏感数据的加密和解密功能
"""
from cryptography.fernet import Fernet
from app.core.config import settings
import base64
import hashlib
import logging
logger = logging.getLogger(__name__)
class EncryptionService:
"""加密服务类"""
_fernet: Fernet = None
@classmethod
def _get_fernet(cls) -> Fernet:
"""获取Fernet加密实例单例模式"""
if cls._fernet is None:
# 使用SECRET_KEY生成Fernet密钥
# Fernet需要32字节的密钥我们使用SHA256哈希SECRET_KEY
key = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
# Fernet需要base64编码的32字节密钥
fernet_key = base64.urlsafe_b64encode(key)
cls._fernet = Fernet(fernet_key)
return cls._fernet
@classmethod
def encrypt(cls, plaintext: str) -> str:
"""
加密明文
Args:
plaintext: 要加密的明文
Returns:
加密后的密文base64编码
"""
if not plaintext:
return ""
try:
fernet = cls._get_fernet()
encrypted = fernet.encrypt(plaintext.encode('utf-8'))
return encrypted.decode('utf-8')
except Exception as e:
logger.error(f"加密失败: {e}")
raise ValueError(f"加密失败: {str(e)}")
@classmethod
def decrypt(cls, ciphertext: str) -> str:
"""
解密密文
Args:
ciphertext: 要解密的密文base64编码
Returns:
解密后的明文
"""
if not ciphertext:
return ""
try:
fernet = cls._get_fernet()
decrypted = fernet.decrypt(ciphertext.encode('utf-8'))
return decrypted.decode('utf-8')
except Exception as e:
logger.error(f"解密失败: {e}")
# 如果解密失败,可能是旧数据未加密,直接返回原值
# 或者抛出异常,让调用者处理
raise ValueError(f"解密失败: {str(e)}")
@classmethod
def encrypt_dict_value(cls, data: dict, key: str) -> dict:
"""
加密字典中指定键的值
Args:
data: 字典数据
key: 要加密的键名
Returns:
加密后的字典
"""
if key in data and data[key]:
data[key] = cls.encrypt(str(data[key]))
return data
@classmethod
def decrypt_dict_value(cls, data: dict, key: str) -> dict:
"""
解密字典中指定键的值
Args:
data: 字典数据
key: 要解密的键名
Returns:
解密后的字典
"""
if key in data and data[key]:
try:
data[key] = cls.decrypt(str(data[key]))
except ValueError:
# 如果解密失败,可能是未加密的数据,保持原值
pass
return data
@classmethod
def is_encrypted(cls, text: str) -> bool:
"""
判断文本是否已加密
Args:
text: 要检查的文本
Returns:
是否已加密
"""
if not text:
return False
try:
# 尝试解密,如果成功则说明已加密
cls.decrypt(text)
return True
except:
return False