import hashlib import base64 import secrets from cryptography.fernet import Fernet from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from flask import current_app import os class SimpleCrypto: """简化的加密工具类,使用 cryptography 包""" def __init__(self, key=None): """ 初始化加密器 :param key: 加密密钥,必须从应用配置中获取 """ if key: self.key = key.encode() if isinstance(key, str) else key else: # 从应用配置获取密钥,生产环境必须设置 key_str = current_app.config.get('AUTH_SECRET_KEY') if not key_str: raise ValueError("AUTH_SECRET_KEY未设置!生产环境必须设置AUTH_SECRET_KEY环境变量!") self.key = key_str.encode('utf-8') # 使用 PBKDF2 生成固定长度的密钥,使用随机盐值 # 注意:这里不能使用固定盐值,否则会降低加密强度 from secrets import token_bytes salt = token_bytes(16) # 随机生成盐值 kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) self.fernet_key = base64.urlsafe_b64encode(kdf.derive(self.key)) self.cipher = Fernet(self.fernet_key) def encrypt(self, data): """ 加密数据 :param data: 要加密的数据(字符串) :return: base64编码的加密结果 """ try: if isinstance(data, str): data = data.encode('utf-8') encrypted_data = self.cipher.encrypt(data) result = base64.b64encode(encrypted_data) return result.decode('utf-8') except Exception as e: raise ValueError(f"加密失败: {str(e)}") def decrypt(self, encrypted_data): """ 解密数据 :param encrypted_data: base64编码的加密数据 :return: 解密后的原始数据 """ try: if isinstance(encrypted_data, str): encrypted_data = encrypted_data.encode('utf-8') data = base64.b64decode(encrypted_data) decrypted_data = self.cipher.decrypt(data) return decrypted_data.decode('utf-8') except Exception as e: raise ValueError(f"解密失败: {str(e)}") def generate_hash(data, salt=None): """ 生成哈希值 :param data: 要哈希的数据 :param salt: 盐值,如果不提供则随机生成 :return: (哈希值, 盐值) 元组 """ if salt is None: salt = secrets.token_hex(16) # 组合数据和盐值 combined = f"{data}{salt}".encode('utf-8') # 生成SHA256哈希 hash_obj = hashlib.sha256(combined) hash_value = hash_obj.hexdigest() return hash_value, salt def generate_signature(data, secret_key): """ 生成签名 :param data: 要签名的数据 :param secret_key: 密钥 :return: 签名 """ combined = f"{data}{secret_key}".encode('utf-8') hash_obj = hashlib.sha256(combined) return hash_obj.hexdigest() def verify_hash(data, hash_value, salt): """ 验证哈希值 :param data: 原始数据 :param hash_value: 要验证的哈希值 :param salt: 盐值 :return: 验证结果 """ computed_hash, _ = generate_hash(data, salt) return computed_hash == hash_value def generate_token(length=32): """ 生成随机令牌 :param length: 令牌长度 :return: 随机令牌字符串 """ return secrets.token_urlsafe(length) def generate_uuid(): """ 生成UUID :return: UUID字符串 """ import uuid return str(uuid.uuid4()) def encrypt_password(password, salt=None): """ 加密密码 :param password: 原始密码 :param salt: 盐值 :return: (加密后的密码, 盐值) """ return generate_hash(password, salt) def verify_password(password, hashed_password, salt): """ 验证密码 :param password: 原始密码 :param hashed_password: 加密后的密码 :param salt: 盐值 :return: 验证结果 """ return verify_hash(password, hashed_password, salt) # 为了兼容性,保留原来的函数名 def AESCipher(key=None): """兼容性包装器""" return SimpleCrypto(key)