214 lines
6.1 KiB
Python
214 lines
6.1 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
激活码生成工具
|
|||
|
|
用于根据客户设备UUID生成激活码
|
|||
|
|
|
|||
|
|
使用方法:
|
|||
|
|
python generate_activation_code.py <设备UUID> <客户密码>
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
python generate_activation_code.py "12345678-1234-1234-1234-123456789ABC" "888888"
|
|||
|
|
|
|||
|
|
参数说明:
|
|||
|
|
设备UUID: 客户设备的主板UUID
|
|||
|
|
客户密码: 与程序中 customerPassword 一致的密码
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
import base64
|
|||
|
|
import hashlib
|
|||
|
|
|
|||
|
|
# ============ 配置参数 ============
|
|||
|
|
ENCRYPT_KEY = b"GetonAgain2026SecretKey!@#$%" # 加密密钥(必须与程序一致)
|
|||
|
|
# ==================================
|
|||
|
|
|
|||
|
|
def encrypt(plain_text: str) -> str:
|
|||
|
|
"""
|
|||
|
|
加密函数 - 与 C++ LicenseManager::encrypt 完全对应
|
|||
|
|
"""
|
|||
|
|
data = plain_text.encode('utf-8')
|
|||
|
|
|
|||
|
|
# 第一步:计算SHA256哈希
|
|||
|
|
hash_obj = hashlib.sha256(data)
|
|||
|
|
hash_bytes = hash_obj.digest()
|
|||
|
|
|
|||
|
|
# 第二步:构造加密数据 = 哈希前8字节 + 原始数据
|
|||
|
|
to_encrypt = hash_bytes[:8] + data
|
|||
|
|
|
|||
|
|
# 第三步:多层加密
|
|||
|
|
encrypted = bytearray()
|
|||
|
|
for i, byte in enumerate(to_encrypt):
|
|||
|
|
c = byte
|
|||
|
|
|
|||
|
|
# 第一层:与主密钥XOR
|
|||
|
|
c = c ^ ENCRYPT_KEY[i % len(ENCRYPT_KEY)]
|
|||
|
|
|
|||
|
|
# 第二层:字节置换(非线性变换)
|
|||
|
|
c = (c * 7 + 13) % 256
|
|||
|
|
|
|||
|
|
# 第三层:与位置相关的混淆
|
|||
|
|
c = c ^ ((i * 31 + 17) % 256)
|
|||
|
|
|
|||
|
|
encrypted.append(c)
|
|||
|
|
|
|||
|
|
# 第四步:Base64编码
|
|||
|
|
return base64.b64encode(bytes(encrypted)).decode('latin-1')
|
|||
|
|
|
|||
|
|
|
|||
|
|
def decrypt(encrypted_text: str) -> str:
|
|||
|
|
"""
|
|||
|
|
解密函数 - 与 C++ LicenseManager::decrypt 完全对应
|
|||
|
|
"""
|
|||
|
|
# Base64解码
|
|||
|
|
encrypted = bytearray(base64.b64decode(encrypted_text.encode('latin-1')))
|
|||
|
|
|
|||
|
|
if len(encrypted) < 9: # 至少8字节校验头 + 1字节数据
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
# 逆向解密
|
|||
|
|
decrypted = bytearray()
|
|||
|
|
for i, byte in enumerate(encrypted):
|
|||
|
|
c = byte
|
|||
|
|
|
|||
|
|
# 逆向第三层:位置混淆
|
|||
|
|
c = c ^ ((i * 31 + 17) % 256)
|
|||
|
|
|
|||
|
|
# 逆向第二层:字节置换的逆运算
|
|||
|
|
# 7 的模逆元是 183 (因为 7 * 183 = 1281 = 5 * 256 + 1)
|
|||
|
|
c = ((c + 256 - 13) * 183) % 256
|
|||
|
|
|
|||
|
|
# 逆向第一层:与主密钥XOR
|
|||
|
|
c = c ^ ENCRYPT_KEY[i % len(ENCRYPT_KEY)]
|
|||
|
|
|
|||
|
|
decrypted.append(c)
|
|||
|
|
|
|||
|
|
# 提取校验头和原始数据
|
|||
|
|
stored_hash = bytes(decrypted[:8])
|
|||
|
|
original_data = bytes(decrypted[8:])
|
|||
|
|
|
|||
|
|
# 验证哈希
|
|||
|
|
computed_hash = hashlib.sha256(original_data).digest()[:8]
|
|||
|
|
if computed_hash != stored_hash:
|
|||
|
|
print("警告: 哈希校验失败,数据可能已损坏")
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
return original_data.decode('utf-8')
|
|||
|
|
|
|||
|
|
|
|||
|
|
def generate_activation_code(uuid: str, password: str) -> str:
|
|||
|
|
"""
|
|||
|
|
生成激活码
|
|||
|
|
格式: encrypt(UUID:password)
|
|||
|
|
"""
|
|||
|
|
plain_text = f"{uuid}:{password}"
|
|||
|
|
return encrypt(plain_text)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def verify_activation_code(activation_code: str, expected_uuid: str, expected_password: str) -> bool:
|
|||
|
|
"""验证激活码是否有效"""
|
|||
|
|
try:
|
|||
|
|
decrypted = decrypt(activation_code)
|
|||
|
|
|
|||
|
|
if not decrypted or ':' not in decrypted:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 使用 rsplit 从右侧分割,只分割一次
|
|||
|
|
parts = decrypted.rsplit(':', 1)
|
|||
|
|
uuid = parts[0]
|
|||
|
|
password = parts[1]
|
|||
|
|
|
|||
|
|
return uuid == expected_uuid and password == expected_password
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"验证错误: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
|
|||
|
|
def save_to_csv(uuid: str, activation_code: str, customer_name: str = ""):
|
|||
|
|
"""
|
|||
|
|
将激活记录保存到CSV文件
|
|||
|
|
"""
|
|||
|
|
import csv
|
|||
|
|
import os
|
|||
|
|
from datetime import datetime
|
|||
|
|
|
|||
|
|
csv_file = "activation_records.csv"
|
|||
|
|
file_exists = os.path.exists(csv_file)
|
|||
|
|
|
|||
|
|
# 获取当前时间
|
|||
|
|
activation_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with open(csv_file, 'a', newline='', encoding='utf-8-sig') as f:
|
|||
|
|
writer = csv.writer(f)
|
|||
|
|
|
|||
|
|
# 如果文件不存在,先写入表头
|
|||
|
|
if not file_exists:
|
|||
|
|
writer.writerow(['序号', '设备UUID', '激活码', '激活时间', '客户名称', '备注'])
|
|||
|
|
|
|||
|
|
# 统计当前记录数作为序号
|
|||
|
|
record_num = 1
|
|||
|
|
if file_exists:
|
|||
|
|
with open(csv_file, 'r', encoding='utf-8-sig') as rf:
|
|||
|
|
record_num = sum(1 for _ in rf) # 包含表头的行数就是新记录的序号
|
|||
|
|
|
|||
|
|
# 写入新记录
|
|||
|
|
writer.writerow([record_num, uuid, activation_code, activation_time, customer_name, ''])
|
|||
|
|
|
|||
|
|
print(f"激活记录已保存到: {csv_file}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"保存CSV记录失败: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
# 检查参数
|
|||
|
|
if len(sys.argv) < 3:
|
|||
|
|
print("用法: python generate_activation_code.py <设备UUID> <客户密码>")
|
|||
|
|
print("示例: python generate_activation_code.py \"12345678-1234-1234-1234-123456789ABC\" \"888888\"")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
uuid = sys.argv[1].strip()
|
|||
|
|
password = sys.argv[2].strip()
|
|||
|
|
|
|||
|
|
if not uuid:
|
|||
|
|
print("错误: UUID 不能为空!")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
if not password:
|
|||
|
|
print("错误: 密码不能为空!")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
# 生成激活码
|
|||
|
|
activation_code = generate_activation_code(uuid, password)
|
|||
|
|
|
|||
|
|
# 验证
|
|||
|
|
if not verify_activation_code(activation_code, uuid, password):
|
|||
|
|
print("错误: 激活码验证失败!")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
# 保存激活码文件
|
|||
|
|
filename = f"license_{uuid[:8]}.gal"
|
|||
|
|
try:
|
|||
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|||
|
|
f.write(activation_code)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"保存文件失败: {e}")
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
# 记录到CSV
|
|||
|
|
save_to_csv(uuid, activation_code)
|
|||
|
|
|
|||
|
|
# 输出结果
|
|||
|
|
print(f"UUID: {uuid}")
|
|||
|
|
print(f"密码: {password}")
|
|||
|
|
print(f"激活码: {activation_code}")
|
|||
|
|
print(f"文件: {filename}")
|
|||
|
|
print("完成")
|
|||
|
|
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
sys.exit(main())
|