news 2026/5/6 17:23:41

告别联网烦恼:手把手教你用AES+RSA为你的Python小工具设计离线授权系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
告别联网烦恼:手把手教你用AES+RSA为你的Python小工具设计离线授权系统

告别联网烦恼:手把手教你用AES+RSA为你的Python小工具设计离线授权系统

独立开发者和小团队常常面临一个两难选择:既希望保护软件收益,又不想投入过多资源搭建复杂的后端授权系统。本文将带你从零开始,用Python实现一套轻量级但足够安全的离线授权方案,结合AES加密和RSA数字签名技术,让你的小工具也能拥有专业级的授权保护。

1. 离线授权系统的核心设计

1.1 为什么选择AES+RSA组合

在离线授权系统中,我们需要解决两个核心问题:数据保密性完整性验证。AES(高级加密标准)以其高效的对称加密特性,非常适合加密授权文件中的敏感信息;而RSA(非对称加密算法)则能提供强大的数字签名能力,确保授权文件不被篡改。

这种组合方案的优势在于:

  • AES加密速度快:适合加密大量数据(如授权信息)
  • RSA签名验证可靠:确保授权文件来源可信
  • 完全离线工作:不需要连接任何服务器
  • 轻量级实现:适合资源有限的独立开发者

1.2 授权文件的结构设计

一个典型的授权文件应包含以下信息(JSON格式示例):

{ "product_id": "your_product_001", "license_type": "professional", "mac_address": "00:1A:2B:3C:4D:5E", "issue_date": "2023-07-20", "expire_date": "2024-07-19", "features": ["feature_a", "feature_b"] }

注意:MAC地址绑定可以防止授权文件被随意复制到其他机器使用,但也要考虑用户更换硬件的合法需求。

2. 密钥管理与生成

2.1 安全生成加密密钥

使用Python的cryptography库可以方便地生成高质量的随机密钥:

from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC import os def generate_aes_key(password: bytes, salt: bytes = None): if salt is None: salt = os.urandom(16) kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) return kdf.derive(password), salt

2.2 RSA密钥对生成与保存

生成RSA密钥对并妥善保存私钥(仅在授权生成端使用):

from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization def generate_rsa_keys(): private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048 ) public_key = private_key.public_key() # 序列化私钥 private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) # 序列化公钥 public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) return private_pem, public_pem

3. 授权文件的生成与加密

3.1 使用AES加密授权信息

以下是完整的授权文件加密流程:

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding import json def encrypt_license(aes_key: bytes, license_data: dict): # 序列化授权数据 license_json = json.dumps(license_data).encode('utf-8') # 应用PKCS7填充 padder = padding.PKCS7(128).padder() padded_data = padder.update(license_json) + padder.finalize() # 生成随机IV iv = os.urandom(16) # 创建加密器 cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv)) encryptor = cipher.encryptor() # 加密数据 encrypted_data = encryptor.update(padded_data) + encryptor.finalize() return iv + encrypted_data

3.2 添加RSA数字签名

为确保授权文件不被篡改,我们需要添加数字签名:

from cryptography.hazmat.primitives.asymmetric import padding as asym_padding from cryptography.hazmat.primitives import hashes def sign_license(private_key_pem: bytes, encrypted_data: bytes): private_key = serialization.load_pem_private_key( private_key_pem, password=None ) signature = private_key.sign( encrypted_data, asym_padding.PSS( mgf=asym_padding.MGF1(hashes.SHA256()), salt_length=asym_padding.PSS.MAX_LENGTH ), hashes.SHA256() ) return signature

4. 客户端验证实现

4.1 解密授权文件

客户端需要实现对应的解密逻辑:

def decrypt_license(aes_key: bytes, encrypted_data: bytes): # 提取IV iv = encrypted_data[:16] ciphertext = encrypted_data[16:] # 创建解密器 cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv)) decryptor = cipher.decryptor() # 解密数据 padded_data = decryptor.update(ciphertext) + decryptor.finalize() # 移除填充 unpadder = padding.PKCS7(128).unpadder() license_json = unpadder.update(padded_data) + unpadder.finalize() return json.loads(license_json.decode('utf-8'))

4.2 验证数字签名

验证签名确保授权文件未被篡改:

def verify_signature(public_key_pem: bytes, encrypted_data: bytes, signature: bytes): public_key = serialization.load_pem_public_key(public_key_pem) try: public_key.verify( signature, encrypted_data, asym_padding.PSS( mgf=asym_padding.MGF1(hashes.SHA256()), salt_length=asym_padding.PSS.MAX_LENGTH ), hashes.SHA256() ) return True except Exception: return False

4.3 有效期检查实现

实现一个简单但有效的时间验证机制:

from datetime import datetime def check_expiry(license_data: dict): if 'expire_date' not in license_data: return True expire_date = datetime.strptime(license_data['expire_date'], '%Y-%m-%d') return datetime.now() < expire_date

5. 系统集成与防破解策略

5.1 将授权系统集成到应用中

以下是一个简单的集成示例:

class LicenseManager: def __init__(self, public_key_pem: bytes, aes_key: bytes): self.public_key = public_key_pem self.aes_key = aes_key self.license_data = None def load_license(self, license_path: str): with open(license_path, 'rb') as f: license_content = f.read() # 分离签名和加密数据 signature = license_content[-256:] # RSA 2048签名长度 encrypted_data = license_content[:-256] if not verify_signature(self.public_key, encrypted_data, signature): raise ValueError("Invalid license signature") self.license_data = decrypt_license(self.aes_key, encrypted_data) if not check_expiry(self.license_data): raise ValueError("License has expired") # 这里可以添加额外的验证逻辑,如MAC地址检查等 return True

5.2 防破解增强措施

虽然任何客户端验证都可能被破解,但我们可以增加破解难度:

  1. 代码混淆:使用PyArmor等工具混淆Python代码
  2. 完整性检查:定期检查关键代码段是否被修改
  3. 多因素验证:结合机器指纹、时间验证等多种因素
  4. 定期更新:定期发布新版本,更换加密方式

提示:没有绝对安全的系统,我们的目标是让破解成本高于软件价格,从而保护大多数合法用户。

6. 授权管理系统实现

6.1 简易授权生成工具

为方便生成授权文件,我们可以实现一个简单的CLI工具:

import click from pathlib import Path @click.command() @click.option('--private-key', required=True, help='Path to RSA private key') @click.option('--aes-key', required=True, help='AES encryption key') @click.option('--output', required=True, help='Output license file path') @click.option('--product-id', required=True) @click.option('--license-type', required=True) @click.option('--mac-address') @click.option('--expire-days', type=int) def generate_license(private_key, aes_key, output, product_id, license_type, mac_address, expire_days): # 加载RSA私钥 with open(private_key, 'rb') as f: private_key_pem = f.read() # 准备授权数据 license_data = { 'product_id': product_id, 'license_type': license_type, 'mac_address': mac_address, 'issue_date': datetime.now().strftime('%Y-%m-%d') } if expire_days: expire_date = (datetime.now() + timedelta(days=expire_days)).strftime('%Y-%m-%d') license_data['expire_date'] = expire_date # 加密授权数据 encrypted_data = encrypt_license(aes_key.encode(), license_data) # 生成签名 signature = sign_license(private_key_pem, encrypted_data) # 保存授权文件 with open(output, 'wb') as f: f.write(encrypted_data + signature) print(f"License generated: {output}")

6.2 授权文件部署策略

在实际部署时,建议采用以下策略:

  1. 分发生成工具:将授权生成工具与主程序分离,仅在需要时运行
  2. 密钥分离存储:将AES密钥和RSA公钥编译进主程序,私钥单独保管
  3. 多级授权:实现试用版、专业版等不同授权级别
  4. 离线激活码:对于无法直接分发授权文件的情况,可采用激活码方式

7. 高级功能扩展

7.1 实现按功能授权

我们可以扩展授权系统,支持按功能授权:

{ "features": { "export_pdf": true, "batch_processing": false, "advanced_analytics": true } }

然后在代码中检查功能授权:

def check_feature(feature_name: str): if not license_manager.license_data: return False features = license_manager.license_data.get('features', {}) return features.get(feature_name, False)

7.2 实现浮动授权

虽然本文主要讨论离线授权,但我们可以实现简单的"浮动授权"机制:

def check_concurrent_usage(): # 检查当前运行的实例数量 process_count = count_running_instances() # 从授权文件中获取允许的最大实例数 max_instances = license_manager.license_data.get('max_instances', 1) return process_count <= max_instances

7.3 授权更新机制

即使离线系统也需要考虑授权更新:

  1. 本地更新:通过新的授权文件替换旧文件
  2. 补丁更新:发布小更新包修改授权信息
  3. 手动输入:在软件界面输入新的授权码

实现一个简单的授权更新接口:

def update_license(new_license_path: str): try: if license_manager.load_license(new_license_path): # 备份旧授权文件 backup_old_license() # 替换为新授权文件 install_new_license(new_license_path) return True except Exception as e: log_error(f"License update failed: {str(e)}") return False

在实际项目中,我发现将核心验证逻辑分散在代码多个位置(而非集中在一处)能有效增加破解难度。同时,定期更换加密密钥和算法(在不同版本中)也能让破解者难以制作通用的破解工具。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/6 17:23:39

免费阿里云动态域名解析:3分钟让家庭服务器7×24小时稳定在线

免费阿里云动态域名解析&#xff1a;3分钟让家庭服务器724小时稳定在线 【免费下载链接】luci-app-aliddns OpenWrt/LEDE LuCI for AliDDNS 项目地址: https://gitcode.com/gh_mirrors/lu/luci-app-aliddns 你是否经常遇到这样的困扰&#xff1a;家里的NAS、监控摄像头或…

作者头像 李华
网站建设 2026/5/6 17:17:28

taocp2_rsa_story

RSA公钥加密算法故事文件 确保互联网安全的算法&#xff1a;RSA 解析5W1H分析 What&#xff08;是什么&#xff09; RSA&#xff08;Rivest-Shamir-Adleman&#xff09;是一种非对称公钥加密算法&#xff0c;由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。它是目前…

作者头像 李华
网站建设 2026/5/6 17:10:54

完全解决Navicat试用期限制:macOS平台3种简单方法重置14天试用

完全解决Navicat试用期限制&#xff1a;macOS平台3种简单方法重置14天试用 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 还…

作者头像 李华